分类 开发语言 下的文章

Win7下插U盘引发的溢出漏洞类安全问题

看了"Introducing the USB Stick of Death",真是有些意外。Win7下的ntfs.sys中竟然有这样一个隐患。下面就是对该文部分内容的大致翻译。

这个bug是由Gynvael Coldwind发现的,并由Mateusz “j00ru” Jurczyk折腾出了利用这个溢出漏洞来提权的操作。

这个安全问题是他们在几个月前检查各设备驱动的安全性和健壮性时发现的,他们的研究重点是NTFS相关的驱动,因为这货异常复杂和庞大,他们认为肯定有一些漏洞还没被发现,而且相关的一些设备驱动程序肯定有一些不用太费劲就可以找到的问题,结果是他们成功了。

当简单的进行插入U盘的操作时,操作系统会自动加载它并会触发一个ntfs.sys中的漏洞。

他们发现了一些可能会被利用的问题,其中一个有趣的问题,虽然并不是太严重,但可以用来本地提权。估计木马编写者们应该很喜欢这样的漏洞。

他们首先是试图找一些能重现的问题,结果在大约17个小时的尝试中,找到了一个可以重复出现的让win7 蓝屏的操作。

结果类似这样:

EXCEPTION_RECORD:  fffff88006fd7fd8 -- (.exr 0xfffff88006fd7fd8)
ExceptionAddress: fffff8800125311e (Ntfs!NtfsAcquirePagingResourceExclusive+0x0000000000000016)
  ExceptionCode: c0000005 (Access violation)
 ExceptionFlags: 00000000
NumberParameters: 2
  Parameter[0]: 0000000000000000
  Parameter[1]: 0000000000000060
Attempt to read from address 0000000000000060

CONTEXT:  fffff88006fd7830 -- (.cxr 0xfffff88006fd7830)
rax=0000000000000702 rbx=fffffa8005c0b180 rcx=0000000000000000
rdx=fffff8a005859ce0 rsi=fffffa8005c0b7e0 rdi=0000000000000000
rip=fffff8800125311e rsp=fffff88006fd8218 rbp=fffff88006fd85a0
r8=0000000000000001  r9=0000000000000000 r10=fffff8a00b254010
r11=fffff88006fd81e8 r12=fffffa8005b36ae0 r13=0000000000000000
r14=0000000000000001 r15=00000000c000026e
iopl=0         nv up ei pl zr na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
Ntfs!NtfsAcquirePagingResourceExclusive+0x16:
fffff880`0125311e 488b4960        mov     rcx,qword ptr [rcx+60h] ds:002b:00000000`00000060=????????????????
Resetting default scope

[...]

STACK_TEXT: 
fffff880`06fd8218 fffff880`01326de4 : [...] : Ntfs!NtfsAcquirePagingResourceExclusive+0x16
fffff880`06fd8220 fffff880`013178a3 : [...] : Ntfs!NtfsPerformDismountOnVcb+0x758
fffff880`06fd8330 fffff880`01317656 : [...] : Ntfs!NtfsLockVolumeInternal+0xf3
fffff880`06fd83a0 fffff880`013053ee : [...] : Ntfs!NtfsLockVolume+0x1f6
fffff880`06fd8480 fffff880`0130553d : [...] : Ntfs!NtfsUserFsRequest+0x2de
fffff880`06fd84c0 fffff880`0102ebcf : [...] : Ntfs!NtfsFsdFileSystemControl+0x13d
fffff880`06fd8560 fffff880`01031aea : [...] : fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x24f
fffff880`06fd85f0 fffff880`010670b5 : [...] : fltmgr!FltPerformSynchronousIo+0x2ca
fffff880`06fd8690 fffff880`01067b38 : [...] : fltmgr!IssueControlOperation+0x395
fffff880`06fd8720 fffff880`031555df : [...] : fltmgr!FltFsControlFile+0x48
fffff880`06fd8780 fffff880`03155d0e : [...] : FsDepends!DepFSSendDismountRequest+0x143
fffff880`06fd87e0 fffff880`0315582d : [...] : FsDepends!DepFSDismountDependencyList+0xd6
fffff880`06fd8840 fffff880`031747a8 : [...] : FsDepends!DependentFSDismountForUnsurface+0x175
fffff880`06fd88a0 fffff880`031749f2 : [...] : vhdmp!VhdmpiHaltActiveSurface+0x78
fffff880`06fd88f0 fffff880`03177156 : [...] : vhdmp!VhdmpiHaltSurfaceOrWait+0xb2
fffff880`06fd8940 fffff880`0316e117 : [...] : vhdmp!VhdmpiRemoveVirtualDisk+0x246
fffff880`06fd8990 fffff880`03166177 : [...] : vhdmp! ?? : [...] :FNODOBFM: [...] :`string'+0x4d87
fffff880`06fd89c0 fffff800`0299e717 : [...] : vhdmp!VhdmpFirstLevelIrpHandler+0x87
fffff880`06fd8a10 fffff800`0299ef76 : [...] : nt!IopXxxControlFile+0x607
fffff880`06fd8b40 fffff800`02687453 : [...] : nt!NtDeviceIoControlFile+0x56
fffff880`06fd8bb0 00000000`76e0138a : [...] : nt!KiSystemServiceCopyEnd+0x13
00000000`010fe548 000007fe`fd49a249 : [...] : ntdll!NtDeviceIoControlFile+0xa
00000000`010fe550 00000000`76ca683f : [...] : KERNELBASE!DeviceIoControl+0x75
00000000`010fe5c0 000007fe`f32d3994 : [...] : kernel32!DeviceIoControlImplementation+0x7f
00000000`010fe610 000007fe`f2c6886b : [...] : VirtDisk!DetachVirtualDisk+0x6c
00000000`010fe670 00000000`ff61f734 : [...] : vdsvd!COpenVDisk: [...] :Detach+0xb3
00000000`010fe6a0 000007fe`fd8823d5 : [...] : vds!CVdsOpenVDisk: [...] :Detach+0x3c
00000000`010fe6e0 000007fe`fd92b68e : [...] : RPCRT4!Invoke+0x65
00000000`010fe740 000007fe`fd8848d6 : [...] : RPCRT4!Ndr64StubWorker+0x61b
00000000`010fed00 000007fe`fee60883 : [...] : RPCRT4!NdrStubCall3+0xb5
00000000`010fed60 000007fe`fee60ccd : [...] : ole32!CStdStubBuffer_Invoke+0x5b [d:\w7rtm\com\rpc\ndrole\stub.cxx @ 1586]
00000000`010fed90 000007fe`fee60c43 : [...] : ole32!SyncStubInvoke+0x5d [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx @ 1187]
00000000`010fee00 000007fe`fed1a4f0 : [...] : ole32!StubInvoke+0xdb [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx @ 1396]
00000000`010feeb0 000007fe`fee614d6 : [...] : ole32!CCtxComChnl: [...] :ContextInvoke+0x190 [d:\w7rtm\com\ole32\com\dcomrem\ctxchnl.cxx @ 1262]
00000000`010ff040 000007fe`fee6122b : [...] : ole32!AppInvoke+0xc2 [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx @ 1086]
00000000`010ff0b0 000007fe`fee5fd6d : [...] : ole32!ComInvokeWithLockAndIPID+0x52b [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx @ 1727]
00000000`010ff240 000007fe`fd8750f4 : [...] : ole32!ThreadInvoke+0x30d [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx @ 4751]
00000000`010ff2e0 000007fe`fd874f56 : [...] : RPCRT4!DispatchToStubInCNoAvrf+0x14
00000000`010ff310 000007fe`fd87775b : [...] : RPCRT4!RPC_INTERFACE: [...] :DispatchToStubWorker+0x146
00000000`010ff430 000007fe`fd87769b : [...] : RPCRT4!RPC_INTERFACE: [...] :DispatchToStub+0x9b
00000000`010ff470 000007fe`fd877632 : [...] : RPCRT4!RPC_INTERFACE: [...] :DispatchToStubWithObject+0x5b
00000000`010ff4f0 000007fe`fd87532d : [...] : RPCRT4!LRPC_SCALL: [...] :DispatchRequest+0x422
00000000`010ff5d0 000007fe`fd892e7f : [...] : RPCRT4!LRPC_SCALL: [...] :HandleRequest+0x20d
00000000`010ff700 000007fe`fd892a35 : [...] : RPCRT4!LRPC_ADDRESS: [...] :ProcessIO+0x3bf
00000000`010ff840 00000000`76dcb68b : [...] : RPCRT4!LrpcIoComplete+0xa5
00000000`010ff8d0 00000000`76dcfeff : [...] : ntdll!TppAlpcpExecuteCallback+0x26b
00000000`010ff960 00000000`76ca652d : [...] : ntdll!TppWorkerThread+0x3f8
00000000`010ffc60 00000000`76ddc521 : [...] : kernel32!BaseThreadInitThunk+0xd
00000000`010ffc90 00000000`00000000 : [...] : ntdll!RtlUserThreadStart+0x1d

- 阅读剩余部分 -

自定义C语言程序的入口函数

今天有人问我C程序编译后入口函数是不是必须得是main,我说不一定,无论是gcc还是vc,其实都是可以自定义的。但具体做起来还是有些繁琐的,没有特殊需求,不会这么做。

一般来说,我们用C语言写的程序,都会有一个

int main(int argc, char *argv)

这样的入口函数,或有时也称为主函数。编译器在链接时会默认程序的入口起始地址为main函数(Windows下函数名稍有不同,但本质上一样)。注意一个程序的入口函数是链接器在生成可执行文件时指定的。

我们其实可以自定义这个函数名而不使用默认入口函数名。

先看看linux下使用gcc如果实现自定义入口函数。

比如这个程序:

#include <stdio.h>

int myentry(int argc, char *argv[])
{
        printf("Start from myentry\n");
        return 0;
}

保存为myentry.c,然后使用下面的命令来编译链接:

gcc -nostartfiles -e myentry myentry.c -o myentry

然后运行:

myentry

可以得到运行结果:

Start from myentry

Segmentation fault

呃,的确有结果了,但新的入口函数结束后程序就崩溃了。显然,在使用了自定义的入口函数后,因为我们是直接使用

return 0;

来试图直接返回操作系统,这样导致程序结束前必要的准备清理工作没做,而gcc为默认的main函数的准备清理动作又没用上,结果就是崩溃。更详细的导致崩溃的原因可以用gdb来调试看看,这里就不深入查找具体原因了。

- 阅读剩余部分 -

Frank is Back!

Frank Borland is Back!

Frank  is Back

有些惊奇,开发过 Sidekick 、 Turbo Pascal 等软件,帮助Borland变成曾经的软件巨头的天才程序员,竟然在这个时候,没有安逸地生活,没有到处投资折腾,而是发出了一声“FRANK IS BACK!”。

他认为软件应该开放、轻量、注重用户体验、跨平台、让人买得起以及重视社区。

不过我们还不知道这是要干嘛,再开发一款Delphi?还是仅仅只是搞笑一下?

OmniThreadLibrary使用笔记-简介

OmniThreadLibrary(http://otl.17slon.com/)是Delphi下的一款用于多线程并发处理的程序库。它的目标是让多线程编程更流畅,成为真正的多线程编程的“可视化”库。它与TThread的区别是让用户专注于线程开发中的任务,而且不是各类线程中的同步调度等。

这套库比较复杂,大致分三部分:

一是用于线程相关辅助功能的代码,比如无锁线程安全的Collection类、阻塞型Collection类和同步等,方便线程中使用;

二是通过对TThread的封装,构建了一套低层的多线程框架,用于简化后台多线程消息的管理、后台任务的管理和线程池的管理等;

三是较高层次的线程框架,框架里已经设计好并抽象提炼了许多现成的多线程方面实现代码,比如并行处理、流水处理和fork/join等,用户只需进行选择并直接编写线程中的工作代码即可,对于多线程开发中一些琐碎的工作以及要很小心处理的同步问题等都已由框架处理好了。

OmniThreadLibrary库因为使用了大量新的Delphi语法,所以需要至少Delphi 2007之后的版本,如果是使用较高层次的框架,则只能在Delphi 2009之后的版本中使用(我建议还是在Delphi XE中用吧),它还不支持FreePascal。目前这套库只能在Windows平台下使用,32bit和64bit都可以。

OmniThreadLibrary库与TThread的区别主要有两点:

1、OmniThreadLibrary库让用户使用中关注的是任务Task而不是线程Thread

2、OmniThreadLibrary库使用消息来取代加锁

这里的任务Task是指需要被运行的那部分工作代码,而线程Thread其实是整个运行环境。

这样,用户关注任务Task,而OmniThreadLibrary库而专注于任务运行的环境。

C语言在函数调用传递的参数中有数组时的处理

segmentfault上有人邀请我回答问题“C语言中参数向量argv问题”。想了想,做了以下答复。

楼上蓝皮鼠 基本上都回答了,我就再啰嗦几句补充一点东西吧;-)

这问题其实挺有趣的,对于argv来说,既然定义成

char *argv[]

那不就是说明argv是一个指向字符串的指针数组,怎么也能左值操作?

我们知道数组名其实就是一个常量,是不能被直接修改的,这是它与指针一个最大的区别。

这里argv与arr最大的区别是一个是函数中的参数,一个是定义的局部变量。

一般可以从两个方面来理解这个问题。

一个方面,正如蓝皮鼠所说的,main函数的原型中argv其实是

char **argv

这样,对于定义成char * argv[]的参数,gcc在编译时会有一个隐式转换,因为这里这两者是是相容的,就算你定义成

char const * argv[]

对于argv来说,这个定义就不相容了。不过一般会有两个结果,要么编译器很严格直接报错,要么会给个警告信息,然后继续把它当成 char **argv 来用。

所以你直接对argv进行左值运行,代码可以被编译通过,就正常了。

另一方面,在C语言中,参数中的数组传递有些特殊。比如下面的代码:

#include <stdio.h>

int func(char *v[])
{
        *++v;

        printf("&v=%x\t v=%x\n",&v,v);
}

int main(int argc, char const* argv[])
{
        char const* arr[]={"1","2","3"};

        printf("&argv=%x\t argv=%x\n",&argv,argv);
        printf("&argc=%x\t argc=%x\n",&argc,argc);

        func(argv);

}

因为main函数是程序的入口函数,是被编译内部定义好的,所以可以再定义一个

int func(char *v[])

结果发现这个v仍然可以进行左值操作。

上面说了参数中数组的传递有些特殊,因为在实际处理参数中的数组时,其实编译器是把它当成一个指针来处理。

比如你定义好一个数组

char arr2[10];

假定有一个函数,其原型如下:

int func2(char p[]);

那么当以下调用发生时:

func2(arr2);

arr2的值会被复制一份到一个内部局部变量指针(堆栈或寄存器)中,这个指针指向arr2[0]的位置。这样arr就被传递进func2函数中了。

同时,这也是在定义函数的参数时,如果参数中有数组,我们一般不用在数组标记中间写上数组长度值的原因,因为没有意义,实际只是把数组的地址进行了传递。
比如:

int func2(char arr[10])

这就是我的理解和说明,希望对你有所帮助。

wordpress的缓存插件cos-html-cache的源码解读

之前在“Blog的选择-Wordpress还是Typecho?”说过Wordpress很笨重,所以这里选择了Typecho。因为一些站需要用Wordpress,所以就得上缓存类插件,一般来说直接用WP Super Cache即可,稳定、易用、效率高。

不过,其实Wordpress还有一款效率更高的缓存类插件,那就是cosbeta(江东,东哥)开发的cos-html-cache,关于cos-html-cache,其原理和功能等方面更多的信息见这里

下面简单解读一下cos-html-cache的源码,我不是这款插件的开发者,不保证解读完全正确。

- 阅读剩余部分 -