# ChildEBP EetAddr
0 f9edabf0 804e4d77 atapi!IdePortDispatch
1 f9edac00 f9a8c061 nt!IopfCallDriver+0s31
2 f9edacl4 f9a8bdS8 CLASSPNP!SubmitTransferPacket+0s82
3 f9edac44 f9a8be49 CLASSPNP!ServiceTransferRequest+0xe4
4 f9edacG8 804e4d77 CLASSPNP!ClassReaHWrite+Dsff
5 f9edac78 f9cd33Gc nt!IopfCallDriver+0s31 0S f9edac88 804e4d77 PartMgr!PmReadTJrite+0x93
7 f9edac98 f985e44c nt!IopfCallDriver+0s31
WARHING: Stack unwind information not available. Following frames may be wrong.
8 f9edad88 f985828d sndisk+0K744c
9 f9edadac 8057efed sndisk+0Kl28d
0a f9edaddc 804fb477 nt!PspSystemThreadStartup+0x34 0b 00000000 00000000 nt!KiThreadStartup+0sl6
Y^<^r
这里sndisk+0xl28d是调用线程读写队列函数的后一条指令,而sndisk+0x744c是线程读写 队列函数体里面执行IoCallDriver函数的后一条指令,还原过滤驱动先于磁盘类设备驱动 或者卷驱动对IPR进行处理,通过获取的四?取得读写指令、读写数据的位置、长度、读写 数据内容等,然后通过一系列复杂的处理(比如:计算读写的重定向的磁盘簇的位置),重 新封装好刚刚处理的IRP,然后把它通过IoCallDriver转发下去,不管是单点还是多点磁 盘还原软件都是用这种方式,不同的是如何计算重定向的位置,不影响读写效率等。以后 我会将自己的学习研究成果与大家一起分享的。我们观察上图1,发现因为构造的3031指 令直接发送总线设备,这就绕过了还原过滤驱动以及一些读写函数110呢的拦截,这就是穿 透还原的真正原理。开始编写代码之前,必须解决两个核心问题:1、如何得到总线设备的 符号连接,因为应用程序是通过符号连接来访为驱动设备的,这里我们采取射成“软件的 方式,如下图2所示,并且使用&扮1#116函数打开设备;2、如何封装5051指令,该指 令核心就是CDB命令描述块的结构,使用DeviceControl函数来发送SCSI指令。

其核心的代码如下:
ULONG GetFuncAddressFromNtdll()
HMODULE hModule;
hModule=GetModuleHandleA("ntdll. dll");
NtOpenDirectoryObject =
(NTOPENDIRECTORYOBJECT)GetProcAddress(hModule, "NtOpenDirectoryObject"); if (!NtOpenDirectoryObject) return 0;
hModule=GetModuleHandleA("ntdll. dll");
NtQueryDirectoryObject =
(NTQUERYDIRECTORYOBJECT)GetProcAddress(hModule, "NtQueryDirectoryObject。; if (!NtQueryDirectoryObject) return 0;
hModu 1 e=GetModu 1 eHand 1 eA(r/ntd 11. dll");
NtOpenSymbo1icLinkObject =
(NTOPENDIRECTORYOBJECT)GetProcAddress(hModule, "NtOpenSymbolicLinkObject"); if (!NtOpenSymbolicLinkObject) return 0;
hMo du 1 e=GetMo du 1 eHand 1 eA (r/ nt d 11. dll");
NtQuerySymbolicLinkObject =
(NTQUERYSYMBOLICLINKOBJECT)GetProcAddress(hModule, "NtQuerySymbolicLinkObjec t");
if (!NtQuerySymbo1icLinkObject) return 0; return 1;
//得到物理磁盘对应的总线设备的符号链接,也就是对应的微端口驱动 ULONG QueryDROSymbollinckName(IN PffSTR DeviceName)
{
HANDLE Openhandle;
NTSTATUS status;
ULONG result; result=0;
/* [〃00806¥1。68〃对应的符号连接〃\\??〃一>来自1化01^逆向
L〃\\SystemRoot〃 对 应 的 符 号 连 接 "\\Device\\HarddiskO\\Partitionl\\Windows"
*/
//判定是否找到是物理磁盘对应的总线设备的符号链接,这里用〃10f«^4〃来判定 if (!wcsstr(DeviceName, L"IDE#Disk")) return 0; else
//注:部分代码有拼写误差(www.jybase.net),
result=l;
\
;
return result;
ULONG GetBusDeviceName()
NTSTATUS status;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa ;
HANDLE OpenObject;
ULONG BufferLength=0x800;
PCHAR Buffer;
ULONG uContext;
ULONG uResult;
ULONG ncount=0;
PDIRECTORY_BASIC_INFORMATION pDirObjectinfo = NULL;
WCHAR ObjName[0x100]={0};
ULONG Result;
Result=0;
INIT_UNICODE_STRING(ObjectName, L〃\\GLOBAL??。;
InitializeObjectAttributes(&oa, &ObjectName, OBJ_CASE_INSENSITIVE, NULL,
NULL);
status = (NtOpenDirectoryObject)(&OpenObject, DIRECTORY_QUERY, &oa);
if (!NT_SUCCESS(status))
return Result; |