好多年没有这样喜欢一个女孩,真的。
今天我们告别了单身,以至于我不知道改以怎样的方式来证实这一刻。
和一个自己喜欢的女孩在一起,这样的故事在我身上已经5年没有发生过了。
希望我的博客帮我记住这一刻。
希望我和她能走得远一些。
希望!!!
谢谢织织。
另外谢谢樊爽,李菲。。。。。
好多年没有这样喜欢一个女孩,真的。
今天我们告别了单身,以至于我不知道改以怎样的方式来证实这一刻。
和一个自己喜欢的女孩在一起,这样的故事在我身上已经5年没有发生过了。
希望我的博客帮我记住这一刻。
希望我和她能走得远一些。
希望!!!
谢谢织织。
另外谢谢樊爽,李菲。。。。。
我已承受不起失败,3岁不是很大的差别,但如果你不理解,或者你并不在意这一切,那么我的付出就是没有意义的。
生理决定心理,心理决定行为。我无意中说出了这么一句,或许她真的对我是有影响的。
我已无法不顾一切的付出,我必须核算我的付出风险。
我从你那里没有得到一丝丝信号,连个毛也没有。
我不得不重新考虑我该怎么做。我必须给自己留以余地。
理智必须压倒一切,虽然这很难。
我宁可不看你一眼,扭头落泪,继而狂奔。也不能葬送了我自己。
88,我要做我自己。自己的失败才是真的失败。
如果有一天你发现我,请你不要惊讶我这么快就做了决定。
要知道,作决定是很痛苦的,我也不例外。
我多么希望能和你一起看那轮圆圆的月亮从东方升起,晚霞照耀着西边“巨乳峰”。
我多么希望能和你一起周末走进影院,哪怕反复看那部《2012》。
我多么希望能和你一起在厨房做一些小东西吃,哪怕它并不好吃。
只要我喜欢,一切都可以。
也许有一天你会抱怨我的沉默。
也许有一天我们还会再遇见。
当然,也许你没有觉得什么不同。
在程序的世界里,没有织女。
我擅自闯入尘世,寻找千百度,可你却不属于人间。
也许上天注定不会有结果。
为自己惋惜。。。。。。
而我只能在这个真正属于我的小角落里记录下这一时刻。
我仍会为你付出
因为我的感觉还在
我只是不能不计风险
我多么希望你能够注意到我的一切
我多么希望你能融入我的世界
可是一切随缘吧
地上牛郎天上星
天上之女地上锦
接下来交给缘分吧
我越发的离不开你,看见你我就会很高兴,和你发短信我都会很踏实,和你做任何事,哪怕是逛街,我都情绪高涨。
已经好多年没有遇到能让我有这种感觉的女孩了。我发自内心的高兴,既为了我遇见你,也为了我的心原来还活着。我不知道是不是在电影院里你激活了我,在或者第一次见面就真的为后面的情节埋下了伏笔。爱就是害怕失去,害怕失去现有的一切,我在自己身上找到了这种东西,我有些不敢和你说,我怕失去。我承受不起。
你的眼神,你柔软的语调,你那老成的造型和小孩的言语之间的差异,没有一样不吸引着我。我真的掉进去了。谢谢你给我带来的一切,也许你并没有在意,但我很感激。
一颗敏感的心就像一个高精度传感器,能感知许多变化。
处理这些变化很痛苦。要处理这些变化而不让别人知晓自己捕获到了这些变化,则无疑是更痛苦的。
我已经很久没有捕获到这中变化了,但捕获到了又有什么用,我依然处理不了。
我仅仅是我而已,能做的很有限,希望你能明白。
这两个星期天天都在搞这个,无数个错误被修正过后,做些笔记以备以后查阅。
为了实现机密文档的保护,文档管理系统必须对所有打开的文件进行监控,因此我们的过滤驱动需要知道当前运行时刻有几个文件被打开,它们分别被打开了几次(同一个文件可能被多次打开)。
用户态和内核态之间的关系
用户态调用CreateFile函数,子系统将请求发给IO管理器,IO管理器会用该函数的
参数生成一个IRP,将此IRP发往底层。过滤驱动截获到IRP,开始对其操作。过滤驱动
操作完了之后会继续往下发,就是调用更下层驱动程序。当下层所有操作完成之后,底
层的完成信息会向上反。这有点像函数的嵌套调用,从最内层函数开始一级一级的返回,
但这只是像。下面是过滤驱动截获返回的CreateFile时的操作。
处理IRP_MJ_CREATE的核心代码():
{
//返回的FsContext为空时,不予以处理
if(FileObject->FsContext == NULL)
{
////////////////////////////////////////DbgPrint("\n\n\n SfCreate: FileObject->FsContext 为 NULL\n\n\n");
status = Irp->IoStatus.Status;
DbgPrint("\n SfCreate() : 建立链表的第一个节点时遭遇 FsContext 为 NULL \n",status);
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
//第一次打开链表时,链表为空,上面for语句无法运行
if(IsListEmpty(&my_list_head))
{
PFILE_CONTEXT FileCtx = (PFILE_CONTEXT)ExAllocatePoolWithTag(PagedPool,sizeof(FILE_CONTEXT),SFLT_POOL_TAG);
if(FileCtx == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
FileCtx->FsContext = FileObject->FsContext;
FileCtx->RefCount = 1;
ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);//多线程安全插入方式
DbgPrint("\n\n SfCreate() : 创建链表的第一个节点:\n ");
DbgPrint("SfCreate() : 第一个节点中 FileCtx->FsContext: %x , FileCtx->RefCount: %u \n\n\n",FileCtx->FsContext,FileCtx->RefCount);
status = Irp->IoStatus.Status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
//搜索链表,查看文件是否已经打开(链表非空时,此搜索才可以进行)
for(p=my_list_head.Flink; p!=&my_list_head; p=p->Flink)
{
PFILE_CONTEXT Elem = CONTAINING_RECORD(p,FILE_CONTEXT,ListEntry);
//文件已打开,计数器加一
if(Elem->FsContext == FileObject->FsContext)
{
KIRQL irql;
DbgPrint("\n\n\nSfCreate() : 遇到已打开过的文件 , 打印Elem节点信息如下 :\n ListEntry: %s, FsContext: %x, RefCount: %u\n",Elem->ListEntry,Elem->FsContext,Elem->RefCount);
if( FileObject->FsContext == NULL)
DbgPrint( "SfCreate() : FileObject->FsContext 为 空");
KeAcquireSpinLock(&my_list_lock,&irql);
Elem->RefCount += 1;
KeReleaseSpinLock(&my_list_lock,irql);
////////////////////////////////////////DbgPrint("\n文件第 %u 次打开\n",Elem->RefCount);
status = Irp->IoStatus.Status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status;
}
}
//文件未打开,填充节点并插入链表
{
//节点内存分配
PFILE_CONTEXT FileCtx = (PFILE_CONTEXT)ExAllocatePoolWithTag(PagedPool,sizeof(FILE_CONTEXT),SFLT_POOL_TAG);
if(FileCtx == NULL)
{
DbgPrint("\n\n SfCreate() : 文件第一次打开时,内存分配失败");
return STATUS_INSUFFICIENT_RESOURCES;
}
//节点内容填充
FileCtx->FsContext = FileObject->FsContext;
FileCtx->RefCount = 1;
//插入节点到链表
ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);//多线程安全插入方式
}
}
大体思路说明:
获取文件对象,确认它是对一个文件的操作(不是就就忽略,直接返回)。然后获取其FsContext,这是文件的全局唯一标识,一个文件不管打开多少次,它只有一个FsContext,不同文件的FsContext也不一样。如果链表为空,直接用这个FsContext填充数据结构,创立一个节点,然后插入链表,之后返回。如果链表不为空,则遍历搜索链表,如果查找到FsContext值一样的节点则说明该文件打开过,只需将该节点数据结构中的RefCount++。如果链表中没有搜索到相应节点,那么就要新建一个节点插入链表。
既然监控就不能只监控打开的,自然也要监控关闭的。
当关闭一个文件窗口的时候,IO管理器会发送一个IRP_MJ_CLEANUP。在处理这个消息的时候,我们需要做的仅仅是从链表中找到那个文件,将其RefCount–。当RefCount值为0的时候,IO管理器就会发送一个IRP_MJ_CLOSE,截获到这个消息,我们就可以将这个文件对应的节点从链表中删除了。
OK!That’s all.
关键用法
A.链表的遍历搜索
if(IsListEmpty(&my_list_head)) { 插入第一个节点 返回 }
for(p=my_list_head.Flink; p!=&my_list_head; p=p->Flink)
从循环体内推出说明没找到,这就需要我们新建节点了
关键是要优先处理空链表的情况
B.链表的插入删除操作
ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);
删除LST_ENTRY p所指向的节点,第一个参数需要用前一个节点的LIST_ENTRY
ExInterlockedRemoveHeadList(p->Blink,&my_list_lock);
C.IRQL锁与互斥体
KeAcquireSpinLock(&my_list_lock,&Irql);
Elem->RefCount -= 1;
KeReleaseSpinLock(&my_list_lock,Irql);
它通过提高IRQL来使其他线程无法执行,解决同步问题
ExAcquireFastMutex( &gSfilterAttachLock );
ExReleaseFastMutex( &gSfilterAttachLock );
这个要相对轻量级
前段时间,受朋友之托。研究一款游戏的pak文件结构,并写出其解压缩代码。
之所以在标题中用“ADPACK32为文件头”是因为虽然后缀都是.pak,但是不同游戏其实现格式就不同。
为了便于观察,在这里我将用一个比较小的文件来做分析。内容如下:

从图中可以观察出以下几点:
1.00H一行是文件头
2.10H的到80H是文件名列表
3.以10H起始到80H,每隔20H就会出现一个文件名 ,多方对比之后发现文件索引块长度20H。前12字节是文件名。后面4字节是文件存储的其实字节位置。中间16字节未知,我觉得是路径之类的东西。如果哪位参透了这16字节的含义,还请指教(shyandsy@tom.com)。但他不影响我们提取数据。
和别的pak文件对比一下,又会发现
1.00H到0BH是完全一样的 =====》ADPACK32。。。。
2.0C到0F是高字节在后的数,这个数乘以20H再加上10H就是数据区启始位置
3.0C到0F是高字节在后的数,这个数乘以20H再加上10H就是数据区启始位置
这样我们就可以提取到包中所有文件。在这里谢谢驱动开发网的网友们对我的支持。
|
刚到新公司,配计算机开发环境,遇到一个问题,由于是外企,所以要用Windows英文版的,以前没安装过,所以也不知道其中的玄机,糊里糊涂就安完了,完成了以后进系统照常使者语言,可是在语言选项里却找不到中文的了,找了好多资料都没有好的解决方法,最后终于找到一个正确的方法了,现在分享给大家: 第一步: 点击Languages页: 选中两个复选框的第二个(Instal files for East Asian languages),不要选第一个,然后点击OK按钮,系统会弹出对话框问你语言包文件在哪,Browse到C:\i386\lang目录,然后选中任何一个文件,点击Open按钮关闭对话框,然后系统开始安装语言包。。。安装完成之后问你是否要重启,选择否! 第二步: 点击Advanced页: 在下拉框里边选择Chinese(PRC),点击OK按钮,然后会弹出对话框问你一个问题,是否使用现有文件,选择"yes",然后又会问你是否要重启windows,选择"yes",重新启动完成之后,就可以读写中文字符,可以安装任何中文输入法了。 |
你看着晾衣架都会露出幸福的微笑。李莎这么说的时候,我在想:“感觉很不错,我给你留下了不错的记忆”。
我曾和你一起逛街,一起购物,一起去唱歌,你曾和我一起吃饭,一起自习,一起看街边药店的鹦鹉。我们认识是因为缘分用列车都装不完,我们分别是因为没有那么多的列车足以承载这么多缘分。
近2年之后我才知道。
你看着晾衣架都会露出幸福的微笑。你朋友这么说的时候,我忽然觉得自己无比的高兴,我给你留下的是纯粹的幸福。
一直觉得你很傻,也一直觉得自己的失败是耻辱,我自信没有一点能输的理由,但是真的输了。
最终做决定只是一瞬间的事情,那天我喝了上大学到现在以来最多的酒,夜里醒来都在狂吐,我看不到希望。我必须作出决定。
我以为你如此坚持应该会有好的结果,其实结果也是惨不忍睹的,脸色和表情出卖了你,你几乎是一个人的力量在支撑两个人,没什么好说的,我也不能够帮你。虽然大家还是朋友。我不能帮你改变现状,这是你自己的选择,是你自己的生活。
而我早已不在思索别人怎么看,不再付出大量的时间和精力去换取别人的记忆。我随波逐流,飘忽不定,一切随缘。
1.VS2005新建工程,然后创建一个项目。
2.对项目名称点右键,进入项目属性。点击“常规”

3.上图右栏“项目默认值”中的“配置类型”,
点击,然后选择“生成文件”
然后“应用”,此时该窗口会变为:

4.点击“NMake”,
(我的WDK安装在 C:\WinDDK 目录中)
单击“包含搜索路径”,进行如下设置
C:\WinDDK\6001.18001\inc\api;
C:\WinDDK\6001.18001\inc\ddk

单击“程序集搜索路径”,进行如下设置

单击" "生成"命令行 " ,作如下设置。
(zymakedrv是一个.bat文件,
C:\WinDDK\6001.18001是WDK的安装路径,
E:后面有一个空格,那是项目路径)
zymakedrv C:\WinDDK\6001.18001(空格,然后接下行)
E: \driver\VS2005\notepad\notepad_head chk WXP -e

5. zymakedrv.bat文件的内容(此文件放在项目目录下)
@echo off
if "%1"=="" goto usage
if "%3"=="" goto usage
if not exist %1\bin\setenv.bat goto usage
call %1\bin\setenv.bat %1 %4 %5
rem changing current directory to specified project
%2
cd %3
build.exe -b -w %6 %7 %8 %9 %10
goto exit
:usage
echo zymakedrv.bat usage:
echo.
echo zymakedrv.bat [DDK_path(%%1)] [project_volume(%%2):] [project_path(%%3)] [fre/chk(%%4)] [wxp/wnet/w2k(%%5)] [other_build_options(%%6+)]
echo.
echo options (%%1),(%%4),(%%5) is for setenv.bat which is in DDK_path(%%1)\bin.
echo options (%%2),(%%3) is for changing current directory to specified project.
echo options (%%6+) is for build.exe which is in DDK_path(%%1)\bin\x86.
echo.
echo e.g.
echo zymakedrv.bat D:\tool\develop_tool\WINDDK\3790.1830 D: \source\c_c++\learn\LearnDriver\DriverTest_1 chk wxp -ceZ
rem %0 %1 %2 %3 %4 %5 %6
echo zymakedrv.bat D:\tool\develop_tool\WINDDK\3790 D: \source\c_c++\learn\LearnDriver\SfilterEx chk WXP -e
rem %0 %1 %2 %3 %4 %5 %6
:exit
7.把微软的sfilter示例代码复制出来,新建一个工程,只要做以上修改。就可以编译。