//科锐十班: 网名米汤
//于武汉桂子花园 2011.12.21 13:47 首先VC 写个用户代码:
#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[])
{
HANDLE hFile;
while (1)
{
printf("Read Going.... 4 !!!\n");
Sleep(4000);
hFile = CreateFile("MYFILE.TXT", // open MYFILE.TXT 25号系统调用服务
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
puts("Could not open file."); // process error
}
CloseHandle(hFile);
}
return 0;
}
//为什么用循环呢,因为我们在系统服务下断点的来的频率太快了,太短了...一下条件断点就无法手标操作虚似机.
//通过od 分析如图:
那么在windbg 中下个条件断点
bp KiFastCallEntry".if @edx== 0x0012FE50{} .else{gc}" 用符号不知道为什么容易 假死机
bp 8053e550 ".if @edx== 0x0012FE50{} .else{gc}" 这样就可以断下来,why!!! Why!!!
这样就在快速系统调用总入口下了一个条件断点,很大的机率上 "确定" 是我们r3程序触发的
nt!KiFastCallEntry:
0008:8053e550 b923000000 mov ecx,23h ecx --> GDT_R3_DATA
0008:8053e555 6a30 push 30h
0008:8053e557 0fa1 pop fs //fs -->KPCR ffdff000
0008:8053e559 8ed9 mov ds,cx
0008:8053e55b 8ec1 mov es,cx //ds,es --> GDT_R3_DATA
0008:8053e55d 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h] //ecx --> TSS
0008:8053e563 8b6104 mov esp,dword ptr [ecx+4] esp 临时堆栈过渡到自己的内核堆栈
0008:8053e566 6a23 push 23h //开始保护R3现场 TRAP_FRAME
0008:8053e568 52 push edx //r3 SS:ESP
0008:8053e569 9c pushfd //r3 状态标志寄存器
0008:8053e56a 6a02 push 2
0008:8053e56c 83c208 add edx,8 //edx --> r3栈中参数块
0008:8053e56f 9d popfd //r0 状态标志寄存器 置0,关中断
0008:8053e570 804c240102 or byte ptr [esp+1],2 //置r3 状态标志寄存器 开中断
0008:8053e575 6a1b push 1Bh //0001 1011 r3 cs GDT_R3_CODE
0008:8053e577 ff350403dfff push dword ptr ds:[0FFDF0304h] //r3 KTRAP_FRAME.eip= iFastSystemCallRet
0008:8053e57d 6a00 push 0 //为了框架统一.压入0,对本次系统调用无意义
0008:8053e57f 55 push ebp
0008:8053e580 53 push ebx //无限r3现场保护
0008:8053e581 56 push esi
0008:8053e582 57 push edi //....
0008:8053e583 8b1d1cf0dfff mov ebx,dword ptr ds:[0FFDFF01Ch] //ebx --> +0x01c SelfPcr : Ptr32 _KPCR
0008:8053e589 6a3b push 3Bh //0011 1011 r3 fs KGDT_R3_TEB
0008:8053e58b 8bb324010000 mov esi,dword ptr [ebx+124h] //esi --> CurrentThread
0008:8053e591 ff33 push dword ptr [ebx] //保存线程原先异常表
0008:8053e593 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh //目前seh置空
0008:8053e599 8b6e18 mov ebp,dword ptr [esi+18h] //ebp --> 当前线程的最高栈顶.
0008:8053e59c 6a01 push 1 //保存先前模式 用户模式
0008:8053e59e 83ec48 sub esp,48h //TRAP_FRAME 预留其它 空间
0008:8053e5a1 81ed9c020000 sub ebp,29Ch //ebp--> 当前KTRAP_FRAME
0008:8053e5a7 c6864001000001 mov byte ptr [esi+140h],1 //设置 当前 先前模式
0008:8053e5ae 3bec cmp ebp,esp
0008:8053e5b0 759a jne nt!KiFastCallEntry2+0x47 (8053e54c)
0008:8053e5b2 83652c00 and dword ptr [ebp+2Ch],0 //KTRAP_FRAME.dr7 = 0
0008:8053e5b6 f6462cff test byte ptr [esi+2Ch],0FFh //当前线程是否在调试状态
0008:8053e5ba 89ae34010000 mov dword ptr [esi+134h],ebp //设置当前线程的当前框架地址
0008:8053e5c0 0f854afeffff jne nt!Dr_FastCallDrSave (8053e410) //如果调试状态跳走
0008:8053e5c6 8b5d60 mov ebx,dword ptr [ebp+60h] //调试相关
0008:8053e5c9 8b7d68 mov edi,dword ptr [ebp+68h] //调试相关
0008:8053e5cc 89550c mov dword ptr [ebp+0Ch],edx //调试相关
0008:8053e5cf c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h //调试相关
0008:8053e5d6 895d00 mov dword ptr [ebp],ebx //调试相关
0008:8053e5d9 897d04 mov dword ptr [ebp+4],edi /调试相关//不开中断 (临时用置为90 这样别的系统调用再也进不来了,就可以安心调试本次调用) eb 8053e5dc 90
0008:8053e5dc fb "sti" 不让她执行 本句代码
0008:8053e5dd 8bf8 mov edi,eax //edi = 系统调用服务号
0008:8053e5df c1ef08 shr edi,8
0008:8053e5e2 83e730 and edi,30h
0008:8053e5e5 8bcf mov ecx,edi //ecx = edi bit11,bit12 00 /10
0008:8053e5e7 03bee0000000 add edi,dword ptr [esi+0E0h] //edi-->ServiceTable
0008:8053e5ed 8bd8 mov ebx,eax //ebx = 系统调用服务号
0008:8053e5ef 25ff0f0000 and eax,0FFFh
0008:8053e5f4 3b4708 cmp eax,dword ptr [edi+8] //检查统调用服务号 的合法性
0008:8053e5f7 0f8345fdffff jae nt!KiBBTUnexpectedRange (8053e342)
0008:8053e5fd 83f910 cmp ecx,10h //是否扩展系统调用
0008:8053e600 751a jne nt!KiFastCallEntry+0xcc (8053e61c) //否则跳走
.......
0008:8053e61c ff0538f6dfff inc dword ptr ds:[0FFDFF638h]
0008:8053e622 8bf2 mov esi,edx //esi-->r3参数块
0008:8053e624 8b5f0c mov ebx,dword ptr [edi+0Ch] //ebx-->参数大小数组
0008:8053e627 33c9 xor ecx,ecx
0008:8053e629 8a0c18 mov cl,byte ptr [eax+ebx] //ecx = 参数块大小
0008:8053e62c 8b3f mov edi,dword ptr [edi] //edi-->系统服务函数指针数组
0008:8053e62e 8b1c87 mov ebx,dword ptr [edi+eax*4] //ebx = 服务函数地址
0008:8053e631 e9f2cb0e01 jmp 8162b228
......
0008:8162b228 e915f4276f jmp hookport+0xa642 (f08aa642)
//...我的机器被谁hook 了?????我不看了.我估计跟360有关,所以还原系统,因为现在只是学习基础!不找没趣吧
.....
//回到正常机器,接着被hook地方(8053e631 ),当然这次是系统正常代码
8053e631 2be1 sub esp,ecx //预留栈空间,准备复制用户参数了
8053e633 c1e902 shr ecx,2 //ecx = 参数个数
8053e636 8bfc mov edi,esp //edi-->当前esp
8053e638 3b35549a5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80559a54)]
8053e63e 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7ec) //if(esi >7fff0000 )(跳走) 检查esi是否r3地址
8053e644 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] //复制r3参数
8053e646 ffd3 call ebx //调用系统服务函数
8053e648 8be5 mov esp,ebp
8053e64a 8b0d24f1dfff mov ecx,dword ptr ds:[0FFDFF124h] //ecx-->CurrentThread
8053e650 8b553c mov edx,dword ptr [ebp+3Ch] //edx=trap_frame.edx 0xffffffff
8053e653 899134010000 mov dword ptr [ecx+134h],edx //Kthread.Trapframe = 0xfffffffff
nt!KiServiceExit:
8053e659 fa cli
8053e65a f7457000000200 test dword ptr [ebp+70h],20000h //trap_frame.eflag测试划是否虚拟8086模式
8053e661 7506 jne nt!KiServiceExit+0x10 (8053e669) //是则跳走
8053e663 f6456c01 test byte ptr [ebp+6Ch],1 //trap_frame.SegCs 是否为r3 选择子
8053e667 7457 je nt!KiServiceExit+0x67 (8053e6c0) //不是则跳走
8053e669 8b1d24f1dfff mov ebx,dword ptr ds:[0FFDFF124h] //ebx-->CurrentThread
8053e66f c6432e00 mov byte ptr [ebx+2Eh],0 //kthread.afterd= 0 清除"警觉" apc 相关
8053e673 807b4a00 cmp byte ptr [ebx+4Ah],0 //kthread.KAPC_STATE.UserApcPending
8053e677 7447 je nt!KiServiceExit+0x67 (8053e6c0) //没有apc挂起
..............
8053e6c0 8b54244c mov edx,dword ptr [esp+4Ch] //edx = ktrap_frame.seh链
8053e6c4 648b1d50000000 mov ebx,dword ptr fs:[50h] //ebx = kpcr.DebugActive 0
8053e6cb 64891500000000 mov dword ptr fs:[0],edx //kpcr.tib.ExceptionList = edx 还原线程seh
8053e6d2 8b4c2448 mov ecx,dword ptr [esp+48h] //ecx = ktrap_frame.PreviousPreviousMode
8053e6d6 648b3524010000 mov esi,dword ptr fs:[124h] //esi-->CurrentThread
8053e6dd 888e40010000 mov byte ptr [esi+140h],cl //kthread.PreviousMode = ecx 还原先前模式
8053e6e3 f7c3ff000000 test ebx,0FFh //当前线程是否在调试
8053e6e9 7579 jne nt!KiSystemCallExit2+0x17 (8053e764) //是,则跳走
8053e6eb f744247000000200 test dword ptr [esp+70h],20000h //trap_frame.eflag测试划是否虚拟8086模式
8053e6f3 0f85eb080000 jne nt!KiExceptionExit+0x12c (8053efe4) //是,则跳走
8053e6f9 66f744246cf8ff test word ptr [esp+6Ch],0FFF8h //trap_frame.cs 高13位
8053e700 0f84b4000000 je nt!KiSystemCallExit2+0x6d (8053e7ba) //为0 则跳走
8053e706 66837c246c1b cmp word ptr [esp+6Ch],1Bh
8053e70c 660fba64246c00 bt word ptr [esp+6Ch],0
8053e713 f5 cmc
8053e714 0f878e000000 ja nt!KiSystemCallExit2+0x5b (8053e7a8)
8053e71a 66837d6c08 cmp word ptr [ebp+6Ch],8
8053e71f 7405 je nt!KiServiceExit+0xcd (8053e726)
8053e721 8d6550 lea esp,[ebp+50h]
8053e724 0fa1 pop fs //还原r3 ss
8053e726 8d6554 lea esp,[ebp+54h] //一路还原.....
8053e729 5f pop edi
8053e72a 5e pop esi
8053e72b 5b pop ebx
8053e72c 5d pop ebp
8053e72d 66817c24088000 cmp word ptr [esp+8],80h //检查trap_frame.cs 选择子的合法性
8053e734 0f87c6080000 ja nt!KiExceptionExit+0x148 (8053f000)
8053e73a 83c404 add esp,4 //跳过trap_errcode
8053e73d f744240401000000 test dword ptr [esp+4],1 // ss:0010:f959fdd0=0000001b 还是检查
nt!KiSystemCallExitBranch:
8053e745 7506 jne nt!KiSystemCallExit2 (8053e74d) //trap_frame.cs是r3 选择子则跳走
......
nt!KiSystemCallExit2:
8053e74d f644240901 test byte ptr [esp+9],1 //trap_frame.tf 位是否为 1 单步状态
8053e752 75f8 jne nt!KiSystemCallExit (8053e74c) //单步状态则跳走
8053e754 5a pop edx //edx = tramp_frame.eip
8053e755 83c404 add esp,4
8053e758 80642401fd and byte ptr [esp+1],0FDh //1111 1101 清掉trap_frame.eflag 位2
8053e75d 9d popfd //还原eflag
8053e75e 59 pop ecx //ecx = tramp_frame.esp r3 的栈顶
8053e75f fb sti //开中断
8053e760 0f35 sysexit //退出内模式
...... sysenter 所做操作: 箭头方向表示 源 赋值给 目标
1,SYSENTER_CS_MSR-->CS 174 (对应KGDT_R0_CODE)
2,SYSENTER_CS_MSR+8-->SS (对应KGDT_R0_DATA)
3,SYSENTER_EIP_MSR-->EIP 176
4,SYSENTER_ESP_MSR-->ESP 175
sysexit 所做操作:
1,SYSENTER_CS_MSR+16-->CS 且 rpl位 自动置3(对应KGDT_R3_CODE)
2, edx --> eip
3, SYSENTER_CS_MSR+24-->SS 且rpl位置3 (对应KGDT_R3_DATA)
4, ecx-->esp
引起反思:
从这这两个指令操作,就可以想像为什么GDT中前几项表项的是那样的顺序!!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: