标 题:
【原创】NTFS XCB定位。
作 者: zkgy
时 间: 2013-07-04,11:19:47
作 者: zkgy
时 间: 2013-07-04,11:19:47
链 接: http://bbs.pediy.com/showthread.php?t=174789
NTFS XCB 定位小小的一个研究。。。顺便纠正一下sudami大牛在《NTFS底层挖掘中》关于通过SCB定位子LCB的一个错误。给研究NTFS的人做一点小小的贡献,欢迎大家踊跃批评。
作者:李光耀
中国民航飞行学院
QQ:447649795E
mail:zkgy2000@126.com
2013-1-1
1、测试说明
WinDbg + Vmware双机调试 (Windows XP SP3)
----------------------------------------------------------------------------------------------------
在C盘建立以下文件结构
123(文件夹)----1.zip
|-----2.exe
|-----456(文件夹)-----1.exe
----------------------------------------------------------------------------------------------------
注意:上述所有文件和文件夹只有在第一次创建或者在被打开过至少一次后他们的SCB才会存在!
-----------------------------------------------------------------------------------------------------
先人工获得各自对应的FILEOBJECT 和SCB,如下图:
先获得对应文件的一个FILE_OBJECT然后,pFileObject->FsContext就是SCB
<<<============================================>>>>
GetObj-->\??\C:\123
FILEOBJECT:816E15F0 SCB:E1D64D20
GetObj-->\??\C:\123\1.zip
FILEOBJECT:81618B88 SCB:E1D038C0
GetObj-->\??\C:\123\2.exe
FILEOBJECT:81615D90 SCB:E1D17570
GetObj-->\??\C:\123\1.zip
FILEOBJECT:816D7098 SCB:E1D038C0
GetObj-->\??\C:\123\456
FILEOBJECT:81933D90 SCB:E1D1F898
GetObj-->\??\C:\123\456\1.exe
FILEOBJECT:81687C78 SCB:E1A97D90
<<<============================================>>>>
C:\123的SCB
地址 数据---------------------------------------------------------------------------------------------------------数据
附件 82897
地址e1d64e80为SCB+0x160,此处的两个指针e1d17710 e1d03a60就是指向子LCB的两个链表,一个指向第一个,一个指向最后一个。遍历其中任何一个链表都可找到123目录下所有被打开过的文件、文件夹的LCB,从LCB可以找到其对应的FCB和SCB以及CCB,就可以控制文件了!当该目录下没有存在任何文件或者没有任何文件被打开过时SCB+0x160与SCB+0x164均指向SCB+0x160,如上文的SCB,如果没有LCB时SCB+0x160 = SCB+0x164 = E1D64D20 + 0x160 = E1D64E80
2、手工定位XCB
2.1现在以SCB+0x160(e1d64e80),的指针指向的内容e1d17710遍历这个链表。
LCB的一些结构如下
e1d17710指向的内容,图中画横线的内容便是e1d17710指向的内容,
地址 数据------------------------------------------------------------------------------------------------------数据
因为LCB.ScbQueue.Flink的偏移为0x8故,这个LCB的地址为e1d17710-0x8 = e1d17708,图中内容实际为123下某个文件的LCB(地址),可以看到这个文件的FCB指针为LCB + 0x10 , *(e1d17708 + 0x14 = e1d174a8
FCB部分结构为:
查看该FCB
地址 数据------------------------------------------------------------------------------------------------------数据
可见FCB.ScbQueu.Flink = e1d175b0;
而SCB部分结构为
故这个LCB->FCB->SCB地址为: FCB.ScbQueu.Flink – (SCB.FcbLinks.Flink在SCB中的偏移0x40)
为e1d175b0– 0x40= e1d175b0对照开始得出的SCB地址,可见LCB FCB SCB 是C:\123\2.exe的。
2.2继续,下一个指向的是e1d1faa8
e1d1faa8指向的内容如下
地址 数据------------------------------------------------------------------------------------------------------数据
根据上文此LCB的地址为: e1d1faa8 – 0x8 = e1d1faa0
LCB->FCB = *(e1d1faa0 + 0x14) = e1d1f7d0
查看FCB
地址 数据------------------------------------------------------------------------------------------------------数据
可见FCB.ScbQueu.Flink = e1d1f8d8;
故这个文件的SCB地址为FCB.ScbQueu.Flink – (SCB.FcbLinks.Flink在SCB中的偏移0x40)
为e1d1f8d8 – 0x40 = E1D1F898根据开始手工获得的SCB地址对照为C:\123\456文件夹的SCB
2.3继续,下一个指向的是e1d03a60
图不再列出,LCB地址为 e1d03a60 -0x8 = e1d03a58 LCB->FCB = e1d037f8
根据FCB得出SCB地址为FCB.ScbQueu.Flink (e1d03900)– (SCB.FcbLinks.Flink在SCB中的偏移0x40)为e1d03900 – 0x40 = E1D038C0对照发现这个是C:\123\1.zip
2.4继续,下一个指向的是e1d64e80
e1d64e80就是开始时C:\123的SCB+0x160的数值。链表遍历完毕。
可见其目录结构为:
C:\123(文件夹SCB :E1D64D20 + 0x160处的LcbQueue.Flink链表)
↓
e1d17710 ----→LCB e1d17708 ->FCB e1d174a8 ->SCB e1d175b0 –>C:\123\2.exe
↓
e1d1faa8 ----→LCB e1d1faa0 ->FCB e1d1f7d0 ->SCB E1D1F898 –>C:\123\456文件夹
↓
e1d03a60 ----→LCB e1d03a58 ->FCB e1d037f8 ->SCB E1D038C0 –>C:\123\1.zip
↓
e1d64e80 ----→ C:\123 SCB + 0x160处的LcbQueue.Flink链表遍历完毕。
找到了C:\123目录下所有打开过的文件的SCB FCB LCB
3.本人归纳的XCB关系
1.用FCB->LcbLinks.Flink 可获得一个Lcb,此Lcb->Scb指向父目录SCB,同时,此Lcb->FcbLink指向自己的FCB.
2.用FCB->ScbLinks.Flink 可获得一个指向自己的Scb.
3.总之,Lcb.FcbLinks 指向自己FCB,
4.一个SCB只能有一个父母FCB,但是一个FCB可以有多个子SCB,也可以有多个父母SCB (这种情况下FCB通过lcb指向父母SCB).
另外Windows 7中XCB中的大多数成员偏移都发生了变化,下面是本人跟踪调试的结果,亲测正确可用!
4.Windows XP sp3下强制移动文件核心代码
(定位XCB并清空CleanupCount)
5.Windows 7下强制移动文件核心代码
(定位XCB并清空CleanupCount)
5.特殊说明
Windows7中为了保护系统文件,移动系统文件的话,必须清空FCB->FcbState中的系统文件标志0x100
6.补充
Windows XP SP3中 sizeof(FCB) = 0xC8
注:本帖由看雪论坛志愿者PEstone 重新将DOC整理排版,若和原文有出入,以原作者附件为准*转载请注明来自看雪论坛@PEdiy.com

NTFS XCB 小小研究
作者:李光耀
中国民航飞行学院
QQ:447649795E
mail:zkgy2000@126.com
2013-1-1
1、测试说明
WinDbg + Vmware双机调试 (Windows XP SP3)
----------------------------------------------------------------------------------------------------
在C盘建立以下文件结构
123(文件夹)----1.zip
|-----2.exe
|-----456(文件夹)-----1.exe
----------------------------------------------------------------------------------------------------
注意:上述所有文件和文件夹只有在第一次创建或者在被打开过至少一次后他们的SCB才会存在!
-----------------------------------------------------------------------------------------------------
先人工获得各自对应的FILEOBJECT 和SCB,如下图:
先获得对应文件的一个FILE_OBJECT然后,pFileObject->FsContext就是SCB
<<<============================================>>>>
GetObj-->\??\C:\123
FILEOBJECT:816E15F0 SCB:E1D64D20
GetObj-->\??\C:\123\1.zip
FILEOBJECT:81618B88 SCB:E1D038C0
GetObj-->\??\C:\123\2.exe
FILEOBJECT:81615D90 SCB:E1D17570
GetObj-->\??\C:\123\1.zip
FILEOBJECT:816D7098 SCB:E1D038C0
GetObj-->\??\C:\123\456
FILEOBJECT:81933D90 SCB:E1D1F898
GetObj-->\??\C:\123\456\1.exe
FILEOBJECT:81687C78 SCB:E1A97D90
<<<============================================>>>>
C:\123的SCB
地址 数据---------------------------------------------------------------------------------------------------------数据
附件 82897
地址e1d64e80为SCB+0x160,此处的两个指针e1d17710 e1d03a60就是指向子LCB的两个链表,一个指向第一个,一个指向最后一个。遍历其中任何一个链表都可找到123目录下所有被打开过的文件、文件夹的LCB,从LCB可以找到其对应的FCB和SCB以及CCB,就可以控制文件了!当该目录下没有存在任何文件或者没有任何文件被打开过时SCB+0x160与SCB+0x164均指向SCB+0x160,如上文的SCB,如果没有LCB时SCB+0x160 = SCB+0x164 = E1D64D20 + 0x160 = E1D64E80
2、手工定位XCB
2.1现在以SCB+0x160(e1d64e80),的指针指向的内容e1d17710遍历这个链表。
LCB的一些结构如下
e1d17710指向的内容,图中画横线的内容便是e1d17710指向的内容,
地址 数据------------------------------------------------------------------------------------------------------数据
因为LCB.ScbQueue.Flink的偏移为0x8故,这个LCB的地址为e1d17710-0x8 = e1d17708,图中内容实际为123下某个文件的LCB(地址),可以看到这个文件的FCB指针为LCB + 0x10 , *(e1d17708 + 0x14 = e1d174a8
FCB部分结构为:
查看该FCB
地址 数据------------------------------------------------------------------------------------------------------数据
可见FCB.ScbQueu.Flink = e1d175b0;
而SCB部分结构为
故这个LCB->FCB->SCB地址为: FCB.ScbQueu.Flink – (SCB.FcbLinks.Flink在SCB中的偏移0x40)
为e1d175b0– 0x40= e1d175b0对照开始得出的SCB地址,可见LCB FCB SCB 是C:\123\2.exe的。
2.2继续,下一个指向的是e1d1faa8
e1d1faa8指向的内容如下
地址 数据------------------------------------------------------------------------------------------------------数据
根据上文此LCB的地址为: e1d1faa8 – 0x8 = e1d1faa0
LCB->FCB = *(e1d1faa0 + 0x14) = e1d1f7d0
查看FCB
地址 数据------------------------------------------------------------------------------------------------------数据
可见FCB.ScbQueu.Flink = e1d1f8d8;
故这个文件的SCB地址为FCB.ScbQueu.Flink – (SCB.FcbLinks.Flink在SCB中的偏移0x40)
为e1d1f8d8 – 0x40 = E1D1F898根据开始手工获得的SCB地址对照为C:\123\456文件夹的SCB
2.3继续,下一个指向的是e1d03a60
图不再列出,LCB地址为 e1d03a60 -0x8 = e1d03a58 LCB->FCB = e1d037f8
根据FCB得出SCB地址为FCB.ScbQueu.Flink (e1d03900)– (SCB.FcbLinks.Flink在SCB中的偏移0x40)为e1d03900 – 0x40 = E1D038C0对照发现这个是C:\123\1.zip
2.4继续,下一个指向的是e1d64e80
e1d64e80就是开始时C:\123的SCB+0x160的数值。链表遍历完毕。
可见其目录结构为:
C:\123(文件夹SCB :E1D64D20 + 0x160处的LcbQueue.Flink链表)
↓
e1d17710 ----→LCB e1d17708 ->FCB e1d174a8 ->SCB e1d175b0 –>C:\123\2.exe
↓
e1d1faa8 ----→LCB e1d1faa0 ->FCB e1d1f7d0 ->SCB E1D1F898 –>C:\123\456文件夹
↓
e1d03a60 ----→LCB e1d03a58 ->FCB e1d037f8 ->SCB E1D038C0 –>C:\123\1.zip
↓
e1d64e80 ----→ C:\123 SCB + 0x160处的LcbQueue.Flink链表遍历完毕。
找到了C:\123目录下所有打开过的文件的SCB FCB LCB
3.本人归纳的XCB关系
1.用FCB->LcbLinks.Flink 可获得一个Lcb,此Lcb->Scb指向父目录SCB,同时,此Lcb->FcbLink指向自己的FCB.
2.用FCB->ScbLinks.Flink 可获得一个指向自己的Scb.
3.总之,Lcb.FcbLinks 指向自己FCB,
4.一个SCB只能有一个父母FCB,但是一个FCB可以有多个子SCB,也可以有多个父母SCB (这种情况下FCB通过lcb指向父母SCB).
另外Windows 7中XCB中的大多数成员偏移都发生了变化,下面是本人跟踪调试的结果,亲测正确可用!
4.Windows XP sp3下强制移动文件核心代码
(定位XCB并清空CleanupCount)
代码:
#define CLEANXCB(p/*PSCB*/) {p->CleanupCount = 0;p->Fcb->CleanupCount = 0;p->Fcb->LinkCount = 1;} NTSTATUS NT5FuckChildren(PSCB pScb)//XP { PULONG pExact = NULL ,pExact_Bak = NULL; PLCB pLcb = NULL; LIST_ENTRY *pList = NULL,*pNew = NULL; PSCB pMyScb = NULL; char Sign = 0; if (!pScb || 0x703 != *(PUSHORT)pScb){ DbgPrint("pScb为NULL或者非文件夹不用Fuck!\n"); return 0; } DbgPrint("----------------进入目录分析----------------\n"); CLEANXCB(pScb) pExact_Bak = pExact = ((PCHAR)pScb + 0x160) ; //DbgPrint("pExact %X *pExact %X\n",pExact,*pExact); if (*pExact == (ULONG)pExact){ DbgPrint("此SCB无子LCB!\n"); DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_UNSUCCESSFUL; } pLcb = (PLCB)(*pExact - 0x8); //DbgPrint("PLCB%XpLcb->ScbLinks.Flink%XpLcb->ScbLinks.Blink%X\n",pLcb,pLcb->ScbLinks.Flink,pLcb->ScbLinks.Blink); if (pLcb->NodeTypeCode != 0x70B){ DbgPrint("此LCB错误!\n"); DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_UNSUCCESSFUL; } while(pLcb->ScbLinks.Flink != pExact ){ DbgPrint("-->LCB: %X FCB: %X SCB: %X\n",pLcb,pLcb->CleanupCount,pLcb->Scb); //=============================================================================== pNew = pList = & ((PFCB)((PCHAR)pLcb+0x14))->ScbQueue; while(!((pList->Blink ==pNew || pList->Flink ==pNew) || pList->Flink==NULL)){ pMyScb = CONTAINING_RECORD(pList->Flink,SCB, FcbLinks.Flink); DbgPrint("----------------MySCB %X NodeTypeCode:%X\n",pMyScb,pMyScb->Header.NodeTypeCode); //-------------------------- CLEANXCB(pMyScb) //------------------------- if (0x703 == pMyScb->Header.NodeTypeCode) {//此SCB代表一个目录 DbgPrint("\t"); NT5FuckChildren(pMyScb); } pList = pList->Flink; } //================================================================================= pLcb = ( ((PUCHAR)pLcb->ScbLinks.Flink) -0x8); } DbgPrint("-->LCB: %X FCB: %X SCB: %X\n",pLcb,pLcb->CleanupCount,pLcb->Scb); pNew = pList = & ((PFCB)pLcb->CleanupCount)->ScbQueue; while(!((pList->Blink ==pNew || pList->Flink ==pNew) || pList->Flink==NULL)){ pMyScb = CONTAINING_RECORD(pList->Flink,SCB, FcbLinks.Flink); DbgPrint("----------------MySCB: %X NodeTypeCode:%X\n",pMyScb,pMyScb->Header.NodeTypeCode); CLEANXCB(pMyScb) if (0x703 == pMyScb->Header.NodeTypeCode) {//此SCB代表一个目录 DbgPrint("\t"); NT5FuckChildren(pMyScb); } pList = pList->Flink; } DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_SUCCESS; }
(定位XCB并清空CleanupCount)
代码:
#defineNT7CLEANXCB(p/*PSCB*/){*(PULONG)((PUCHAR)p+0x60)=0;*(PULONG)(((PUCHAR)(*(PULONG)(( PUCHAR)p + 0x50))) + 0xC4) = 0;} NTSTATUS NT7FuckChildren(PSCB pScb) { PULONG pExact = NULL ,pExact_Bak = NULL; PLCB pLcb = NULL; LIST_ENTRY *pList = NULL,*pNew = NULL; PSCB pMyScb = NULL; char Sign = 0; DbgPrint("----------------进入目录分析----------------\n"); NT7CLEANXCB(pScb) pExact_Bak = pExact = (PULONG)((PCHAR)pScb + 0x168) ; //DbgPrint("pExact %X *pExact %X\n",pExact,*pExact); if (*pExact == (ULONG)pExact){ DbgPrint("此SCB无子LCB!\n"); DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_UNSUCCESSFUL; } pLcb = (PLCB)(*pExact - 0x8); //DbgPrint("PLCB%XpLcb->ScbLinks.Flink%XpLcb->ScbLinks.Blink%X\n",pLcb,pLcb->ScbLinks.Flink,pLcb->ScbLinks.Blink); if (pLcb->NodeTypeCode != 0x70B){ DbgPrint("此LCB错误!\n"); DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_UNSUCCESSFUL; } while( (PULONG)pLcb->ScbLinks.Flink != pExact /*&& (PULONG) pLcb->ScbLinks.Blink != pExact */){ DbgPrint("-->LCB: %X FCB: %X SCB: %X\n",pLcb,*(PULONG)(( PUCHAR)pLcb + 0x18),pLcb->Scb); //=============================================================================== pNew = pList = & ((PFCB)(*(PULONG)(( PUCHAR)pLcb + 0x18)))->LcbQueue;//实际为ScbQueue while(!((pList->Blink ==pNew || pList->Flink ==pNew) || pList->Flink==NULL)){ pMyScb = (PSCB)((PUCHAR)pList->Flink - 0x48); DbgPrint("----------------My SCB%X NodeTypeCode:%X\n",pMyScb,pMyScb->Header.NodeTypeCode); //-------------------------- NT7CLEANXCB(pMyScb) //------------------------- if (0x703 == *(PUSHORT)(pMyScb)) {//此SCB代表一个目录 DbgPrint("\t"); NT7FuckChildren(pMyScb); } pList = pList->Flink; } // ================================================================================= pLcb = (PLCB)( ((PUCHAR)pLcb->ScbLinks.Flink) -0x8); } DbgPrint("-->LCB: %X FCB: %X SCB: %X\n",pLcb,*(PULONG)(( PUCHAR)pLcb + 0x18),pLcb->Scb); //=============================================================================== pNew = pList = & ((PFCB)(*(PULONG)(( PUCHAR)pLcb + 0x18)))->LcbQueue; while(!((pList->Blink ==pNew || pList->Flink ==pNew) || pList->Flink==NULL)){ pMyScb = (PSCB)((PUCHAR)pList->Flink - 0x48); DbgPrint("----------------My SCB%X NodeTypeCode:%X\n",pMyScb,pMyScb->Header.NodeTypeCode); //-------------------------- NT7CLEANXCB(pMyScb) //------------------------- if (0x703 == *(PUSHORT)(pMyScb)) {//此SCB代表一个目录 DbgPrint("\t"); NT7FuckChildren(pMyScb); } pList = pList->Flink; } DbgPrint("----------------目录分析完毕----------------\n"); return STATUS_SUCCESS; }
Windows7中为了保护系统文件,移动系统文件的话,必须清空FCB->FcbState中的系统文件标志0x100
代码:
NTSTATUS ModifyFcbSystemFileFlag(PVOID pScb,char bRm) { PFCB pFcb = NULL; PULONG pLg = NULL; pFcb = (PFCB)(*(PULONG)((PCHAR)pScb + 0x50)); if (!pFcb){ DbgPrint("修改系统属性时,FCB获取失败\n"); return; } pLg = (PULONG)((PUCHAR) pFcb + 4); if (bRm){ DbgPrint("去除系统文件属性\n"); *pLg = *pLg &(~0x100);} else{ DbgPrint("增加系统文件属性\n"); *pLg |=0x100; } DbgPrint("State:%X\n",*pLg); DbgPrint("修改系统属性成功!\n"); }
Windows XP SP3中 sizeof(FCB) = 0xC8
注:本帖由看雪论坛志愿者PEstone 重新将DOC整理排版,若和原文有出入,以原作者附件为准*转载请注明来自看雪论坛@PEdiy.com