首页
社区
课程
招聘
360保险箱进程保护分析(续)
发表于: 2010-3-23 21:11 9396

360保险箱进程保护分析(续)

2010-3-23 21:11
9396

分析版本:360保险箱v3.0正式版(2010.1.1下载)
分析工具:syser debugger、ida
使用平台:XP sp2虚拟机

续上文:http://bbs.pediy.com/showthread.php?t=108378

3、代理服务分析
  
   在上文调用系统服务处设置条件断点:bpx 8053E636 if eax==115(115系统服务号),即可跟入
NtWriteVirtualMemory对应的代理服务:(Syser代码,对应IDA的函数sub_125c4)

FAB6D5C4      MOV    EDI,EDI
FAB6D5C6      PUSH   EBP
FAB6D5C7      MOV    EBP,ESP
FAB6D5C9      SUB    ESP,000000AC
FAB6D5CF      PUSH   ESI
FAB6D5D0      MOV    [EBP-2C],EDX
FAB6D5D3      MOV    [EBP-28],ESI
FAB6D5D6      MOV    EAX,[EBP+0C]
FAB6D5D9      MOV    [EBP-20],EAX
FAB6D5DC      MOV    EAX,[EBP+10]
FAB6D5DF      AND    [EBP-10],+00
FAB6D5E3      MOV    [EBP-1C],EAX
FAB6D5E6      MOV    EAX,[EBP+14]
FAB6D5E9      MOV    [EBP-18],EAX
FAB6D5EC      MOV    EAX,[EBP+18]
FAB6D5EF      MOV    [EBP-14],EAX
FAB6D5F2      MOV    EAX,[EBP+08]
FAB6D5F5      MOV    [EBP-24],EAX

--------------------入口参数检查 ---------------------------------------------------
FAB6D5F8      LEA     EAX,[EBP-0C]     //出口参数检查记数
FAB6D5FB      PUSH   EAX
FAB6D5FC      LEA    EAX,[EBP+FFFFFF54] //出口参数指针
FAB6D602      PUSH   EAX
FAB6D603      LEA    EAX,[EBP-6C]    //用于检查出口参数的函数指针
FAB6D606      PUSH   EAX
FAB6D607      LEA    EAX,[EBP-24]    //calc进程句柄
FAB6D60A      PUSH   EAX
FAB6D60B      PUAH   +1A               //过滤函数索引
FAB6D60D      CALL   FAB6BC0A        //入口参数检查
FAB6D612      CMP    EAX,C0000503
FAB6D617      MOV    [EBP-8],EAX
FAB6D61A      JNZ     FABD623         //如检查成功
FAB6D61C      XOR    EAX,EAX
FAB6D61E      JMP     FAB6D6EB
FAB6D623      TEST    EAX,EAX
FAB6D625      JL      FAB6D6EB         //如被拦截
FAB6D62B      MOV    EAX,[FAB74070]
FAB6D630      MOV    ESI,EAX
FAB6D632      TEST   AH,10
FAB6D635      MOV   EAX,[FAB740E4]  //代理服务表基址
FAB6D63A      JZ      FAB6D66B          //如果是SSDT服务序号

---------------------取原始服务地址(for SSDTShadow)---------------------------
FAB6D63C      AND    ESI,00000FFF
FAB6D642      PUSH   [EAX+ESI*4+00001F4C]
FAB6D649      CALL    MmIsAddressValid //检查代理服务表中原服务地址有效性
FAB6D64F      TEST    AL,AL
FAB6D651      JZ       FAB6D661           //如无效
FAB6D653      MOV    EAX,[EAB740E4]
FAB6D658      MOV    EAX,[EAX+ESI*4+00001F4C] //取代理服务表中原服务地址
FAB6D65F      JMP     FAB6D68F
FAB6D661      MOV    EAX,[FAB73F24]
FAB6D666      MOV    EAX,[EAX+ESI*4]    //取原始SSDTShadow中服务地址
FAB6D669      JMP     FAB6D68F

--------------------取原始服务地址(for SSDT)------------------------------------
FAB6D66B      SHL     ESI,02
FAB6D66E      PUSH   [ESI+EAX+04]
FAB6D672      CALL    MmIsAddressValid   //检查代理服务表中原服务地址有效性
FAB6D678      TEST    AL,AL
FAB6D67A      JZ      FAB6D687              //如无效
FAB6D67C      MOV    EAX,[FAB740E4]
FAB6D681      MOV    EAX,[ESI+EAX+04] //取代理服务表中原服务地址
FAB6D685      JMP     FAB6D68F
FAB6D687      MOV    EAX,[FAB73F2C]
FAB6D68C      MOV    EAX,[ESI+EAX]     //取原始SSDT中服务地址

------------------- 调用取到的原始服务地址 --------------------------------------
FAB6D68F      MOV    [EBP-04],EAX
FAB6D692      MOV    EDX,[EBP-2C]
FAB6D695      MOV    ESI,[EBP-28]
FAB6D698      PUSH   [EBP+18]
FAB6D69B      PUSH   [EBP+14]
FAB6D69E      PUSH   [EBP+10]
FAB6D6A1      PUSH   [EBP+0C]
FAB6D6A4      PUSH   [EBP+08]
FAB6D6A7      CALL    [EBP-04]  //调用取到的服务地址
FAB6D6AA      MOV    [EBP-08],EAX

------------------- 出口参数检查 ------------------------------------------------
FAB6D6AD      XOR    ESI,ESI
FAB6D6AF      CMP    [EBP-0C],ESI
FAB6D6B2      JNA     FAB6D6E8   //如不需出口参数检查
FAB6D6B4      MOV    EAX,[EBP+ESI*4-6C] // 用于检查出口参数的函数指针
FAB6D6B8      TEST   EAX,EAX
FAB6D6BA      MOV    ECX,[EBP+ESI*4+FFFFFF54] //出口参数指针
FAB6D6C1      MOV    [EBP+08],EAX
FAB6D6C4      MOV    [EBP+0C],ECX
FAB6D6C7      JZ       FAB6D6E2
FAB6D6C9      PUSH   [EBP+0C]
FAB6D6CC      PUSH   [EBP-08]      //调用原始服务的返回值
FAB6D6CF      LEA     EAX,[EBP-24]
FAB6D6D2      PUSH   EAX
FAB6D6D3      PUSH   +1A          //过滤函数索引
FAB6D6D5      CALL    [EBP+08]    //出口参数检查
FAB6D6D8      MOV    [EBP+10],EAX
FAB6D6DB      MOV    EAX,[EBP+10]
FAB6D6DE      TEST    EAX,EAX
FAB6D6E0      JL       FAB6D6EB
FAB6D6E2      INC     ESI
FAB6D6E3      CMP     ESI,[EBP-0C] //是否检查完毕
FAB6D6E6      JC      FAB6D6B4    //继续检查
FAB6D6E8      MOV    EAX,[EBP-08]
FAB6D6EB      POP     ESI
FAB6D6EC      LEAVE
FAB6D6ED      RET     0014

    该函数首先检查传入的用户态参数,如果无需拦截则执行原始服务例程序,并根据返回的相关
参数决定是否对出口参数做检查。

继续跟入入口参数检查函数FAB6D60D  CALL  FAB6BC0A :(Syser代码,对应IDA函数
sub_10c0a)

FAB6BC0A      MOV    EDI,EDI
FAB6BC0C      PUSH   EBP
FAB6BC0D      MOV    EBP,ESP
FAB6BC0F      SUB     ESP,+0C
FAB6BC12      AND     [EBP-04],+00
FAB6BC16      CMP     [EBP+08],4B    //过滤函数索引值范围
FAB6BC1A      PUSH    EBX
FAB6BC1B      PUSH    ESI
FAB6BC1C      PUSH    EDI
FAB6BC1D      JNC     FAB6BC92        //如果过滤函数索引越限
FAB6BC1F      MOV     ESI,[FAB73F34]  //过滤规则表基址
FAB6BC25      TEST    ESI,ESI
FAB6BC27      JZ       FAB6BC8A       //如过滤规则表不存在
FAB6BC29      MOV     EDI,[EBP+14]
FAB6BC2C      MOV     EBX,[EBP+10]
FAB6BC2F      SUB      EBX,EDI
FAB6BC31      CMP      [ESI+08],+00  //过滤规则表中过滤函数是否存在
FAB6BC35      JZ        FAB6BC83     //如不存在
FAB6BC37      MOV     EAX,[EBP+8]   //传入的过滤函数索引
FAB6BC3A      MOV     EAX,[ESI+EAX*4+0C] //取规则表中对应索引的过滤函数地址
FAB6BC3E      TEST     EAX,EAX
FAB6BC40      MOV     [EBP-08],EAX
FAB6BC43      JZ        FAB6BC83     //如该过滤函数不存在
FAB6BC45      AND     [EBP+14],+00  
FAB6BC49      AND     [EBP+10],+00
FAB6BC4D      LEA      EAX,[EBP+10] //出口参数检查函数指针数组
FAB6BC50      PUSH    EAX
FAB6BC51      LEA      EAX,[EBP+14] //出口参数指针数组
FAB6BC54      PUSH    EAX
FAB6BC55      PUSH    [EBP+0C]      //calc进程句柄
FAB6BC58      PUSH    [EBP+08]      //过滤函数索引
FAB6BC5B      CALL    [EBP-08]       //调用索引到的过滤函数
FAB6BC5E      MOV     [EBP-0C],EAX
FAB6BC61      MOV     EAX,[EBP-0C]
FAB6BC64      TEST    EAX,EAX
FAB6BC66      JL       FAB6BC94
FAB6BC68      MOV     EAX,[EBP+14]
FAB6BC6B      TEST    EAX,EAX
FAB6BC6D      JZ       FAB6BC83     //出口参数指针存在
FAB6BC6F      CMP     [EBP-04],+10  //出口参数指针最多16个
FAB6BC73      JNC     FAB6BC83
FAB6BC75      INC     [EBP-04]
FAB6BC78      MOV    [EBX+EDI],EAX
FAB6BC7B      MOV    EAX,[EBP+10] //出口参数检查指针
FAB6BC7E      MOV    [EDI],EAX
FAB6BC80      ADD    EDI,+04
FAB6BC83      MOV    ESI,[ESI+04]
FAB6BC86      TEST    ESI,ESI
FAB6BC88      JNZ     FAB6BC31
FAB6BC8A      MOV    EAX,[EBP+18]
FAB6BC8D      MOV    ECX,[EBP-04] //出口参数检查指针的数量
FAB6BC90      MOV    [EAX],ECX
FAB6BC92      XOR    EAX,EAX
FAB6BC94      POP     EDI
FAB6BC95      POP     ESI
FAB6BC96      POP     EBX
FAB6BC97      LEAVE
FAB6BC98      RET     0014

    该函数调用索引值对应的过滤函数(见前文过滤规则表数据结构),返回用于做出口参数检查
的函数指针的地址及指针个数。

4、过滤函数分析

继续跟入过滤函数FAB6BC5B  CALL  [EBP-08],此时代码已经进入驱动safeboxkrnl.sys。
(Syser代码,IDA对应的函数sub_141c8)

FACDF1C8      MOV    EDI,EDI
FACDF1CA      PUSH   EBP
FACDF1CB      MOV    EBP,ESP
FACDF1CD      PUSH   -01
FACDF1CF      PUSH    FACE3180
FACDF1D4      PUSH    FACE29E2
FACDF1D9      MOV     EAX,FS[00000000]
FACDF1DF      PUSH    EAX
FACDF1E0      MOV     FS:[0],ESP
FACDF1E7      PUSH    ECX
FACDF1E8      PUSH    ECX
FACDF1E9      SUB     ESP,0454
FACDF1EF      MOV     EAX,[FACE3CD4]
FACDF1F7      MOV     [EBP-34],EAX
FACDF1F7      PUSH    EBX
FACDF1F8      PUSH    ESI
FACDF1F9      PUSH    EDI
FACDF1FA      MOV     [EBP-18],ESP
FACDF1FD      AND     [EBP-24],+00
FACDF201      MOV     [EBP-2C],01         //放行标志位
FACDF208      AND     [EBP-28],+00        //向R3询问标志位
FACDF20C      AND     [EBP-20],+00        //进程对象的PEPROCESS指针
FACDF210      CALL    ExGetPreviousMode  //调用来自用户态还是内核心态
FACDF216      MOVSX  EAX,AL
FACDF219      TEST    EAX,EAX
FACDF21B      JNZ      FACDF224
FACDF21D      XOR     EAX,EAX
FACDF21F      JMP      FACDF402
FACDF224      MOV     EAX,[EBP+0C]           //calc进程句柄
FACDF227      CMP     [EAX],-01                //句柄是否为空
FACDF22A      JNZ      FACDF233
FACDF22C      XOR     EAX,EAX
FACDF22E      JMP      FACDF402
FACDF233      AND     [EBP-04],+00
FACDF237      CALL     PsGetCurrentProcessID  //得到当前进程 ID
FACDF23C      MOV     [EBP+FFFFB9C],EAX
FACDF242      CMP      [FACE53E0],+00
FACDF249      JZ        FACDF294
FACDF24B      MOV     EAX,[EBP+FFFFFB9C]
FACDF251      OR       EAX,+03
FACDF254      XOR      EAX,+03
FACDF257      MOV     ECX,[FACE53E4]
FACDF25D      MOV     ECX,[ECX+14]
FACDF260      MOV     ECX,[ECX+18]
FACDF263      OR       ECX,+03
FACDF266      XOR      ECX,+03
FACDF269      CMP      EAX,ECX                //是否保险箱自身进程
FACDF26B      JZ        FACDF28F
FACDF26D      MOV     EAX,[EBP+FFFFFB9C]
FACDF273      OR       EAX,+03
FACDF276      XOR      EAX,+03
FACDF279      MOV      ECX,[FACE53E4]
FACDF27F      MOV      ECX,[ECX+14]
FACDF282      MOV      ECX,[ECX+14]
FACDF285      OR        ECX,+03
FACDF288      XOR      ECX,+03
FACDF28B      CMP      EAX,ECX               //是否保险箱自身进程
FACDF28D      JNZ      FACDF294
FACDF28F      JMP       FACDF3B3
FACDF294      MOV     [EBP+FFFFFBA8],01
FACDF29E      CALL     PsGetCurrentProcessID //得到当前进程 ID
FACDF2A3      MOV     [EBP+FFFFFBAC],EAX
FACDF2A9      PUSH    0104
FACDF2AE      LEA      EAX,[EBP+FFFFFDC0]
FACDF2B4      PUSH    EAX
FACDF2B5      LEA      EAX,[EBP+FFFFFBA8]
FACDF2BB      PUSH    EAX
FACDF2BC      CALL    FACDDAD6            //当前进程是否为保险箱保护对象
FACDF2C1      MOV     [EBP-24],EAX
FACDF2C4      CMP     [EBP-24],+00
FACDF2C8      JZ       FACDF2D6            //如果非保护进程
FACDF2CA      MOV     [EBP-2C],01          //如果是保护进程则放行标志置位
FACDF2D1      JMP      FACDF3B3
FACDF2D6      PUSH    +00
FACDF2D8      LEA      EAX,[EBP-20]        //OUT参数:引用对象的PEPROCESS指针
FACDF2DB      PUSH    EAX
FACDF2DC      PUSH    +00
FACDF2DE      PUSH    +00
FACDF2E0      PUSH    +01
FACDF2E2      MOV     EAX,[EBP+0C]                //calc进程句柄
FACDF2E5      PUSH    [EAX]
FACDF2E7      CALL    ObReferenceObjectByHandle //根据calc句柄获得引用的进程对象
FACDF2ED      MOV     [EBP-30],EAX
FACDF2F0      CMP      [EBP-30],+00
FACDF2F4      JNL       FACDF2FB
FACDF2F6      JMP       FACDF3B3
FACDF2FB      CALL     IoGetCurrentProcess        //得到当前进程对象
FACDF301      CMP      [EBP-20],EAX              //当前进程对象是否为calc进程对象
FACDF304      JNZ      FACDF30B
FACDF306      JMP      FACDF3B3
FACDF30B      LEA       EAX,[EBP+FFFFFBA0]
FACDF311      PUSH     EAX
FACDF312      PUSH     [EBP-20]
FACDF315      CALL     FACDCF86 //根据进程对象的PEPROCESS指针得到calc进程的PID
FACDF31A      MOVZX   EAX,AL
FACDF31D      TEST     EAX,EAX
FACDF31F      JNZ       FACDF326
FACDF321      JMP       FACDF3B3
FACDF326      MOV     EAX,[EBP+FFFFFBA0]
FACDF32C      MOV     [EBP+FFFFFBAC],EAX
FACDF332      PUSH    0104
FACDF337      LEA      EAX,[EBP+FFFFFDC0]
FACDF33D      PUSH    EAX
FACDF33E      LEA      EAX,[EBP+FFFFFBA8]
FACDF344      PUSH    EAX
FACDF345      CALL    FACDDAD6        //calc进程是否为保险箱设置的保护对象
FACDF34A      MOV    [EBP-24],EAX
FACDF34D      CMP    [EBP-24],+00
FACDF351      JZ       FACDF3AC
FACDF353      CALL    FACDD6DE        //检查当前进程是否在放行或拦截列表中
FACDF358      MOV    [EBP+FFFFFB98],EAX
FACDF35E      MOV    EAX,[EBP+FFFFFB98]
FACDF364      MOV    [EBP+FFFFFB94],EAX
FACDF36A      CMP    [EBP+FFFFFB94],+00
FACDF371      JZ      FACDF387            //不在放行和拦截列表中
FACDF373      CMP    [EBP+FFFFFB94],+01
FACDF37A      JZ      FACDF3A3            //在放行列表中
FACDF37C      CMP    [EBP+FFFFFB94],+02
FACDF383      JZ      FACDF39D            //在拦截列表中
FACDF385      JMP     FACDF3AA
FACDF387      AND    [EBP-2C],+00        //标志:拦截
FACDF38B      MOV    [EBP-28],01         //询问标志置位
FACDF392      MOV   EAX,[EBP+FFFFFBAC]
FACDF398      MOV   [EBP-1C],EAX         //保存calc进程PID
FACDF39B      JMP    FACDF3AA
FACDF39D      AND   [EBP-2C],00          //标志:拦截
FACDF3A1      JMP    FACDF3AA
FACDF3A3      MOV   [EBP-2C],01          //标志:放行
FACDF3AA      JMP    FACDF3B3
FACDF3AC      MOV   [EBP-2C],01
FACDF3B3      OR     [EBP-04],-01
FACDF3B7      JMP    FACDF3C4
FACDF3B9      XOR   EAX,EAX
FACDF3BB      INC    EAX
FACDF3BC      RET
FACDF3BD      MOV    ESP,[EBP-18]
FACDF3C0      OR      [EBP-04],-01
FACDF3C4      CMP     [EBP-20],+00
FACDF3C8      JZ       FACDF3D7            //calc进程的PEPROCESS指针如果为空
FACDF3CA      MOV    ECX,[EBP-20]
FACDF3CD      CALL   ObfDereferenceObject //释放对象
FACDF3D3      AND    [EBP-20],+00
FACDF3D7      CMP    [EBP-28],+00
FACDF3DB      JZ      FACDF3F3
FACDF3DD      PUSH   +00
FACDF3DF      LEA     EAX,[EBP+FFFFFDC0]
FACDF3E5      PUSH    EAX
FACDF3E6      PUSH    [EBP-1C]             //calc 进程 PID
FACDF3E9      PUSH    +04
FACDF3EB      CALL    FACDDF84            //向R3传递消息,询问“放行”或“禁止”
FACDF3F0      MOV     [EBP-2C],EAX
FACDF3F3      CMP     [EBP-2C],+00
FACDF3F7      JZ       FACDF3FD
FACDF3F9      XOR     EAX.EAX              //放行返回0
FACDF3FB      JMP     FACDF402
FACDF3FD      MOV     EAX,C0000001       //需要拦截,返回负值
FACDF402      MOV    ECX,[EBP-10]
FACDF405      MOV    FS:[0],ECX
FACDF40C      MOV    ECX,[EBP-34]
FACDF40F      CALL    FACE29CE
FACDF414      POP     EDI
FACDF415      POP     ESI
FACDF416      POP     EBX
FACDF417      LEAVE
FACDF418      RET     0010

    本例中当前进程是指注入器进程。从注释中可以整理出该函数的基本逻辑:

    A、  如果当前进程是保险箱进程则放行。
    B、  如果当前进程是保险箱保护对象则放行。
    C、  如果当前进程打开的进程是保险箱保护对象,则检查当前进程文件是否在保险
    箱设置的放行或拦截列表中:如在放行列表中则放行,如在拦截列表中则拦截,如
    不在这两个表中则向R3传递询问消息,由用户手动选择放行或拦截。

    当跟踪代码到FACDF371处,可以知道注入器进程并未在拦截或放行列表中,进
而FACDF3EB处的向R3发送询问消息的函数得以执行,桌面弹出选择对话框,当用户
手动选择“禁止”后,会导致代理服务FAB6D6A7处原始系统服务例程无法得到调用,
进而注入失败,达到保护目的。

四、总结

    对于被保护进程的恶意控制总要调用到相关的系统服务,这些系统服务例程被重新
设计成代理服务,并以一张代理服务表的形式通过新的调度函数(见F997C811)完成
索引,供系统调用。可见,保险箱架构的枢纽正是这个位于系统内核KiFastCallEntry
函数内hook代码中的调度函数。而代理服务的本质则是通过入口、出口参数的检查完
成对进程破坏行为的过滤。

    究竟有多少代理服务被创建呢,看看IDA加载的hookport.sys中代理服务表建立函
数sub_1832c就知道了,此处不再列举。同样地,打开 safeboxkrnl.sys 的函数
sub_15bca,我们可以看到有多少代理服务调用过的入口参数过滤函数被创建。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 70
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
good article
2010-3-23 22:14
0
游客
登录 | 注册 方可回帖
返回
//