201310-狸猫换太子-穿别人的鞋,走自己的路-Spider[4st TeAm]

狸猫换太子----穿别人的鞋,走自己的路(另类思维实现Ring0隐藏文件)

10号的时候接了朋友一个编程方面的订单,要求从头开始写一个精简版的远程控制软件,其他功能不说了,主要是一个,要求设置文件访问权限,要可设置4类(可访问,可写,可删除,可见)

根据字面意思很容易可以理解,可访问就是是否可以读(换句话说,要是不能访问的话,当然也就不能写了),可见的话就是是否可以被看见,可删除就是是否能被删除;

那么第一个想法是使用SSDT HOOK,但是自己重头开始写一个驱动比较累,而且调试比较费时间,特别麻烦;朋友告知想要这个功能是因为网上有一款免费软件Easy File Locker可以实现这个功能,非常的方便;于是就产生了一个想法

能否逆向Easy File Locker,看看它是怎么实现的

于是下载到了这个软件,界面很简单;

支持锁定文件以及锁定文件夹,从左到右依次是可访问,可写,可删除,可见;

简单的看了下,这个程序没有加壳,也没有做什么反调试的防护措施(围观群众:靠,你刚不是说了是免费软件吗,还做个屁的反调试呀)

那么就从这个OK的按钮事件开始逆向之旅吧;找按钮事件之类的就不多说了,相信Team里的好基友们都比我更强大;

经过一段跟踪之后,来到了00410C35函数,之所以锁定到这里是因为…我一路F8,看看哪个CALL以后,文件被锁定了,那么就F7进去,如此反复,最终发现是00410C35里面的2个API函数FLTLIB.FilterConnectCommunicationPort和FLTLIB.FilterSendMessage实现了锁定文件的功能(啥,2个API函数就能实现锁定文件,这不可能吧)

百度一下这两个函数的资料,看看是做什么用的,

http://technet.microsoft.com/zh-cn/ff540460(v=vs.85)

介绍是: FilterConnectCommunicationPort opens a new connection to a communication server port that is created by a file system minifilter.

英文果断看不懂,百度翻译一下

FilterConnectCommunicationPort 开辟了一个新的连接到通信服务器端口,通过文件系统创建的新框架。

虽然…百度翻译翻译出来的东西中国人和外国人都看不太懂,但是大致上我们还是能够了解了, FilterConnectCommunicationPort开辟一个新的连接到通信服务器端口;那么不难理解FilterSendMessage就是通过这个通信服务器端口传输数据了;来了解下参数吧:

HRESULT FilterConnectCommunicationPort(

_In_ LPCWSTR lpPortName, // "\XlkfsPort"

_In_ DWORD dwOptions, // NULL

_In_opt_ LPCVOID lpContext, // NULL

_In_ WORD dwSizeOfContext, // NULL

_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, // NULL

_Out_ HANDLE *hPort // 返回句柄的缓冲区指针

);

HRESULT FilterSendMessage(

_In_ HANDLE hPort, // 通信端口句柄

_In_opt_ LPVOID lpInBuffer, // 输入缓冲区

_In_ DWORD dwInBufferSize, // 输入缓冲区大小

_Out_ LPVOID lpOutBuffer, // 输出缓冲区 (可以为NULL)

_In_ DWORD dwOutBufferSize, // 输出缓冲区大小 (可以为NULL)

_Out_ LPDWORD lpBytesReturned // 实际写入数据

);

那么FilterConnectCommunicationPort函数我们显然没有必要去详细了解,只要知道它的lpPortName参数就可以了,因为它就是一个连接函数,换句话说,如果我们要关注文件操作,那么我们应该关注WriteFile和ReadFile,对于CreateFile,我们只要关心FileName就OK了;

那么在FilterSendMessage的FF25位置下断,发现这个函数从开始执行到retn,这个函数共被调用了2次,2次的数据分别是:

第一次(由于该文件的格式都是 tmpXXX.tmp~1,所以将其命名为 tmp0_1)

009847C8 58 66 73 53 03 00 00 00 5C 00 3F 00 3F 00 5C 00 XfsS



...\.?.?.\.

009847D8 43 00 3A 00 5C 00 44 00 4F 00 43 00 55 00 4D 00 C.:.\.D.O.C.U.M.

009847E8 45 00 7E 00 31 00 5C 00 41 00 44 00 4D 00 49 00 E.~.1.\.A.D.M.I.

009847F8 4E 00 49 00 7E 00 31 00 5C 00 4C 00 4F 00 43 00 N.I.~.1.\.L.O.C.

00984808 41 00 4C 00 53 00 7E 00 31 00 5C 00 54 00 65 00 A.L.S.~.1.\.T.e.

00984818 6D 00 70 00 5C 00 74 00 6D 00 70 00 37 00 45 00 m.p.\.t.m.p.7.E.

00984828 2E 00 74 00 6D 00 70 00 7E 00 31 00 00 00 00 00 ..t.m.p.~.1.....

第二次(由于该文件的格式都是 tmpXXX.tmp~0,所以将其命名为 tmp0_0)

009847C8 58 66 73 53 05 00 00 00 5C 00 3F 00 3F 00 5C 00 XfsS...\.?.?.\.

009847D8 43 00 3A 00 5C 00 44 00 4F 00 43 00 55 00 4D 00 C.:.\.D.O.C.U.M.

009847E8 45 00 7E 00 31 00 5C 00 41 00 44 00 4D 00 49 00 E.~.1.\.A.D.M.I.

009847F8 4E 00 49 00 7E 00 31 00 5C 00 4C 00 4F 00 43 00 N.I.~.1.\.L.O.C.

00984808 41 00 4C 00 53 00 7E 00 31 00 5C 00 54 00 65 00 A.L.S.~.1.\.T.e.

00984818 6D 00 70 00 5C 00 74 00 6D 00 70 00 32 00 30 00 m.p.\.t.m.p.2.0.

00984828 46 00 2E 00 74 00 6D 00 70 00 7E 00 30 00 00 00 F...t.m.p.~.0...

那么这里显然是传输了一个临时文件的名称过去,给谁呢?当然是给驱动了;那么我们简单看下这两个tmp,发现这两个tmp里面出现了我们要求锁定的文件的名称,以及一些其他的数据,来做个小实验:

把这个文件名称修改一下,发现被锁定的文件就变了,那么我们大致可以猜出这个程序的结构了:

Ring3程序从用户这里得到了一些信息,比如”需锁定文件的路径”,”要锁定成什么属性”,”是锁定文件还是锁定文件夹”等;然后组合成一个tmp文件,接着把这个tmp文件的路径传输到Ring0下,由Ring0内核模块去实现锁定文件的功能;

那么,嘿嘿,邪恶的我们就考虑,能否分析出这2个tmp的数据结构,由此自己构造2个tmp,然后用FilterConnectCommunicationPort和FilterSendMessage传输给其内核模块,由此来实现一开始说的”狸猫换太子”呢;呵呵,当然是可以的;因为我已经做好了;

具体分析相信各位都会,这里就贴一段分析结果吧:

首先是tmp0_1的数据结构

typedef struct _DATA

{

DWORD Count; // 固定为1

BYTE[80] PathVoluemeName; // Easy File Locker所在磁盘的盘符,通过GetVolumeNameForVolumeMountPoint可以获得,注

意,这里是UNICODE字符串

DWORD VolueNameCheck; // 将VolumeName转换为大写,比如{0171E958-DB33-11E2-8658-806D6172696F},然后累加每个

字符的ASCII值,比如:0x089D

DWORD Zero; // 固定为0

DWORD Zero; // 固定为0

DWORD Zero; // 固定为0

DWORD RelativeRouteEndOffset; // (RelativeRoute数据结束位置)相对于(数据起始地址)的偏移

// 计算方法:strlenW(RelativeRoute) + 0x64(RelativeRoute前所有数据的大小) + 0x02

(RelativeRoute的结束符长度,2个0x00)

BYTE[?] RelativeRoute; // Easy File Locker的相对路径 + \*,但是注意必须全部是大写的,且是UNICODE字符串

// 比如Easy File Locker存放在C:\AAAA下,那么该值就是 UNICODE"\AAAA\*"

WORD strEnd; // 0x0000,UNICODE字符串结束符

BYTE[96] Zero; // 0x60(96)个字节的0x00

DWORD RecyleBinEndOffset; // (RecycleBin数据结束位置)相对于(RelativeRoute的结束位置)的偏移;

// 计算方法:2 * strlenW(RecycleBin) + 0x02(结束符长度) + 0x60(Zero数据的长度) +

0x04(RecyleBinEndOffset的长度);

BYTE[?] RecycleBin; // 固定为UNICODE"\$RECYCLE.BIN\*"

WORD strEnd; // 0x0000,UNICODE字符串结束符

BYTE[96] Zero; // 0x60(96)个字节的0x00

DWORD Buffer3EndOffset; // (Buffer3数据结束位置)相对于(RecycleBin的结束位置)的偏移

// 计算方法:2 * strlenW(Buffer3) + 0x02(结束符长度) + 0x60(Zero数据的长度) +

0x04(Buffer3EndOffset的长度);

BYTE[?] Buffer3; // 固定为UNICODE"\RECYCLER\*",具体含义不明

WORD strEnd; // 0x0000,UNICODE字符串结束符

BYTE[96] Zero; // 0x60(96)个字节的0x00

DWORD Buffer4EndOffset; // (Buffer4数据结束位置)相对于(Buffer3的结束位置)的偏移

// 计算方法:2 * strlenW(Buffer4) + 0x02(结束符长度) + 0x60(Zero数据的长度) +

0x04(Buffer4EndOffset的长度);

BYTE[?] Buffer4; // 固定为UNICODE"\SYSTEM VOLUME INFORMATION\*",具体含义不明

WORD strEnd; // 0x00,UNICODE字符串结束符

BYTE[80] PathVoluemeName1; // 要锁定的文件所在磁盘盘符,通过GetVolumeNameForVolumeMountPoint可以获得,注意,这

里是UNICODE字符串

DWORD VolueName1Check; // 将VolumeName1转换为大写,比如{0171E958-DB33-11E2-8658-806D6172696F},然后累加每

个字符的ASCII值,比如:0x089D

DWORD Zero; // 固定为0

DWORD Zero; // 固定为0

DWORD Access; // 实际上只要4个二进制位就可以了,也就是半个字节,4个二进制位分别代表:可删除 可写

可见 可访问,0表示勾选,1表示未勾选

DWORD FileNameEndOffset; // (FileName数据结束位置)相对于(Buffer4数据结束位置)的偏移

// 计算方法:strlenW(FileName)*2 + 2 + 0x50(PathVoluemeName1的长度) + 5 * 4(5个

DWORD的长度)

BYTE[?] FileName; // 欲锁定文件的相对路径,比如要锁定E:\yy\Delphi7例子.exe,那么该值为

UNICODE"\YY\DELPHI7例子.EXE"

}DATA,*PDATA;

然后是tmp0_0的数据结构:

[Common]

Count = Locker File Count; // 被锁定的文件总数量

[x] // 第x个文件,从0开始计数

Path = Lock File Path

Type = BOOL(File = 0, Folder = 1)

Access = 可删除 可写 可见 可访问

1 0 1 0

那么我们只要根据这个结构,来构造出2个tmp数据,接着传输给Ring0即可;

接着的话是怎么加载它的驱动了,因为我们知道,它主要的实现是驱动代码,那么我们要用FilterConnectCommunicationPort和FilterSendMessage的话,首先是要加载它的驱动,否则一切免谈啦;

刚开始以为是个NT式驱动,拿加载器搞了半天,全部失败..纠结死我了,后来又分析了下它的安装程序做的事情,才发现是个WDM驱动,在安装的时候会在Temp文件夹下生成一个xlkfs.inf,这个inf就是驱动程序的安装inf;

仅仅有这个inf还不够,经调试分析,发现在右键inf->安装之前,还需要在注册表添加2项内容,一项是Ring3下就可以添加,另一项却要Ring0的权限,因为第二项所在位置是锁定权限的;平时只可读,不可写;那么百度了一下相关修改权限的代码,终于找到了,呵呵,具体的请看源码

大致流程是:根据用户的操作(Lock or UnLock),以及参数(Path, Access)来生成一个tmp0_0文件,然后根据这个tmp0_0来生成tmp0_1文件,接着连接驱动

tmp0_0(实际上是一个ini文件)的生成按如下流程:
(1).首先复制C:\WINDOWS\XLKFS.INI到任意一个磁盘暂存(我是复制到C:\下)
(2).取出其Common主项下的Count子项(该子项表示目前已锁定文件的总数量)
(3).如果是锁定文件,则根据Count的值来添加Access,Type,Path三个属性
(4).如果是解锁文件,则根据欲解锁文件的Path值来遍历ini文件,删除与其对应的项

接着按照tmp0_0来生成一份tmp0_1,具体结构在源码及文章中都有写

请注意:源码的OnInitDialog函数中包含了加载驱动的代码,如果测试完毕后需要卸载,请安装Easy File Locker,然后执行其卸载程序,源码中并不包含卸载代码!

201310-狸猫换太子-穿别人的鞋,走自己的路-Spider[4st TeAm]

时间: 2024-10-10 04:05:25

201310-狸猫换太子-穿别人的鞋,走自己的路-Spider[4st TeAm]的相关文章

.NET 高级架构师 WEB架构师 ------走正确的路

本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路,如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序员们,你们有没有下面几种感觉? 一.              我的工作就是按时完成领导交给我的任务,至于代码写的怎样,知道有改进空间,但没时间去改进,关键是领导也不给时间啊. 二.              我发现我的水平总是跟不上技术的进步,有太多想学的东西要学,Jquery用的人最近比较多啊,听

(转)WEB架构师成长之路之一-走正确的路

本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路,如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序员们,你们有没有下面几种感觉? 一. 我的工作就是按时完成领导交给我的任务,至于代码写的怎样,知道有改进空间,但没时间去改进,关键是领导也不给时间啊. 二. 我发现我的水平总是跟不上技术的进步,有太多想学的东西要学,Jquery用的人最近比较多啊,听说最近MVC比较火,还有LINQ,听说微软又有Sil

WEB架构师成长之路——走正确的路

本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路,如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序员们,你们有没有下面几种感觉? 一.我的工作就是按时完成领导交给我的任务,至于代码写的怎样,知道有改进空间,但没时间去改进,关键是领导也不给时间啊. 二.我发现我的水平总是跟不上技术的进步,有太多想学的东西要学,Jquery用的人最近比较多啊,听说最近MVC比较火,还有LINQ,听说微软又有Silve

OSChina 周五乱弹——走别人的路,让别人无路可走~

周五!!!今天是个好日子啊- 北京的雾霾听说再次袭来,大面积复活了... @大大菠萝:悟空问:师傅,前面云雾缭绕是不是到大雷音寺了? 师傅说:你这泼猴,出家人不说诳语,那是北京,那里的人生活在仙境里,据说幸福指数全国第一,要不你留下吧.悟空说:不,我不留下,我想去西天.师傅说:你这泼猴,留在北京是去西天最快的方式了. 大家准备好防范措施了吗? 北京的同学们 新研发的过滤PM2.5微粒的口罩已经上市了 口罩我有,健康在手- 这回我们去北京会带上家伙的,到时候你们就可以看到帅帅的我了,呃呵呵- 去北

为何滴滴会走Uber之路,研发无人驾驶?

近日,滴滴出行宣布完成新一轮超过55亿美元融资,以支持其全球化战略的推进和前沿技术领域的投资.其中,无人驾驶汽车将是这笔资金重要的投资方向.此前,滴滴在全球范围内的追赶对象Uber不断在无人汽车领域发力,滴滴此举,是否是要加强自身在出行行业的话语权和主动权?再加上特斯拉.谷歌.福特等不断在无人驾驶上做文章,立志做下一个巨鳄的滴滴,自然不会放过这个大热风口. 消除司机边界成本滴滴野心显露 原本网约车条例的出台,让共享打车企业都松了一口气--总算被承认了.但是在各地具体实施以来,却让共享打车企业遭遇

坚持走自己的路

昨天下午因事去了原来的公司,看到公司的发展变化,看到原来项目能够顺利完成,看到原来在一个战壕里的兄弟朋友,心里难免有那么一丝丝的忧伤. 忧伤只为自己,而非其它人或物.我知道从原来的公司出来创业,懂我的人支持,不懂的人怀疑,还有一部分人心中暗暗欢喜,自己却只有坚持. 不管是支持.怀疑或心中窃笑的人,我都要感谢你们!感谢支持我的兄弟朋友,因为有你们我才能一直这么坚持地走下去.感谢怀疑我的朋友,因为有你们我才不断地怀疑自己,能够及时调整.感谢心中窃笑的人们,因为有你们才让我有更大的动力去改变.去坚持.

走了多少路,回头看一看

今天是周末,偶然翻看一下初高中同学的相册,强烈的思念起那个无知无识的时代.我才发现,随着视野的开阔,知识的丰富,世界观的成熟,我并没有变得多么开心.幸福.这绝不是说我想回到那个时代,认为那时的我强过现在的我.只不过这种偶然的追思让我有一种感觉,那就是只有作为同代人的我,才有着更多的存在感.我认同那些回忆,尽管现在可能彼此已经不再熟悉.这种认同感使我短暂的抛却种种疑虑,变得豁然开朗. 我想接触实在的过去.我想在某种程度上和过去联系的更紧密.看看那时的我,尽管心智不成熟,但是却有我现在所不太具备的一

手游发展现状该如何走好运营路

社交的需求是互联网用户最大的需求.时间久了根深蒂固的这么认为.游戏成功与否的根本是是否能够做好社交,再精致的游戏,如果无法形成用户之间有效的互动都是无法生存下去的,尤其是国内的环境,沉溺与单机RPG游戏的用户本身也需要游戏之外的群体交流讨论.而第一代PC端游用户进入社会,游戏时间碎片化和移动互联网的发展注定了游戏从端游走向页游,在到现在的手游,这些都是必然的趋势.而13年手游的爆发仅仅是个开始,而手游之后的发展,游戏本身注定是技术(画面.技术)越来越成熟:运营上也会逐渐在带有明显移动属性的情况下

SDN走开源之路

被博科大中国区副总裁于肇烈称为业内首个商业支持的开源SDN(软件定义网络)解决方案--博科Vyatta控制器将于近期上市.博科Vyatta控制器是用户从传统网络向软件网络平滑过渡的一个关键节点,在有力地促进SDN和NFV(网络功能虚拟化)实施的同时,由于它是一个开源产品,还可以有效避免网络方案被厂商锁定. 在从传统数据中心架构向云计算架构迁移的过程中,无论是从虚拟化还是开源的角度去考量,计算和存储已经先行一步,现在架构转换的一个关键点或者说难点就是网络.虽然从软件定义的角度看,SDN比其他软件定