首页
社区
课程
招聘
逆向RING0程序从这里开始
发表于: 2006-12-6 21:41 35203

逆向RING0程序从这里开始

2006-12-6 21:41
35203
【文章标题】: 逆向RING0程序从这里开始
【文章作者】: 笨笨雄
【作者邮箱】: nemo314@gmail.com
【使用工具】: IDA

接触RING 0之前,以为得学很多东西,一大堆驱动开发的知识。不过后来想了想,驱动壳等其他不直接访问硬件的程序为了兼容性,不可能真的直接访问硬件,也就是那些是基于硬件抽象层之上的,而且大部分使用的还是系统提供的API(RING0下使用的API称为NATIVE API)。事情一下子变简单了,除非你想通过逆向硬件厂商驱动,自己编写优化硬件或者超频程序。

虽然这是纯静态分析,但是我希望通过分析整个驱动,你会理解一些RING0下的机制,并且懂得在动态调试中应该如何下断点定位代码。

在开始之前,感谢rockhard的源代码和已编译好的驱动,这样我就可以不必学习WINDDK的使用了。你可以在下面链接的附件中得到:

http://bbs.pediy.com/showthread.php?s=&threadid=35626
初步实现系统级拦截应用程序取硬盘物理序列号

Rockhard发表上述文章时的目标是通过简单修改REGMON驱动部分的源代码完成拦截应用程序取硬盘物理序列号的功能,难免有不足之处。个人对源代码的不成熟评论并不针对Rockhard。

学习逆向时,我的方法是先看看高级语言代码编译后究竟是怎么样的。或许最后我还是得学习WINDDK的使用,编写代码,编译,反汇编,它会解答一些疑问。下面让我来以源码和反汇编代码对照的形式来说明RING0下的一些机制。

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )

DriverEntry,驱动程序的入口函数,驱动的一些初始化操作,将在这里进行。象RING3那样,程序通过堆栈访问DriverObject和RegistryPath。而在IDA,反汇编后是这样子:“; int __stdcall start(PDRIVER_OBJECT DriverObject,HANDLE Handle)”第二个参数的名字有点不同,不过不重要,我们知道,其实它是一样的。

.text:000105A0                 push    7
.text:000105A2                 pop     ecx
.text:000105A3                 mov     esi, offset s_DeviceHdhook ; "\\Device\\HDHOOK"
.text:000105A8                 lea     edi, [ebp+regnameNt]
.text:000105AE                 push    9
.text:000105B0                 rep movsd
.text:000105B2                 movsw
.text:000105B4                 pop     ecx
.text:000105B5                 mov     esi, offset s_DosdevicesHdh ; "\\DosDevices\\HDHOOK"
.text:000105BA                 lea     edi, [ebp+regnameDos]
.text:000105C0                 push    206B6444h       ; Tag
.text:000105C5                 rep movsd
.text:000105C7                 movsw
.text:000105C9                 mov     esi, offset s_Start ; "Start"
.text:000105CE                 lea     edi, [ebp+SourceString]
.text:000105D1                 movsd
.text:000105D2                 movsd
.text:000105D3                 movsd
.text:000105D4                 mov     esi, [ebp+Handle]
.text:000105D7                 movzx   eax, word ptr [esi]
.text:000105DA                 inc     eax
.text:000105DB                 inc     eax
.text:000105DC                 push    eax             ; NumberOfBytes
.text:000105DD                 push    1               ; PoolType
.text:000105DF                 call    ds:ExAllocatePoolWithTag

前面一大堆代码,都是因为下面3个局部变量的定义,编译器会生成一段代码,先将这些字符移进堆栈,然后再使用。

WCHAR                   deviceNameBuffer[]  = L"\\Device\\"DRIVER_NAME;
WCHAR                   deviceLinkBuffer[]  = L"\\DosDevices\\"DRIVER_NAME;
WCHAR                   startValueBuffer[] = L"Start";

从逆向的角度来看,象这种静态字符变量,如果换成全局变量,或者可以获得更高的运行效率和更小的程序。值得注意的是NATIVE API的调用,第一个参数入栈后的几行代码,仍然是局部变量的初始化,这编译器让我想起扭曲变形的介绍。000105D4的代码是从堆栈中取得DriverEntry的第二参数,它是一个UNICODE_STRING结构,从MSDN中搜索到的说明(如无特别说明,一切资料都是从MSDN中搜索得到):

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING *PUNICODE_STRING;

从000105D7处的代码来看,该结构在反汇编是:

  WORD  Length
  WORD  MaximumLength
  DWORD  Buffer(指向字符的指针)

通过逆向RtlInitUnicodeString,可知上述结构中的 MaximumLength成员,其实就相当于Length + sizeof(UNICODE_NULL)。关于调用ExAllocatePoolWithTag的第三参数PoolType:

typedef enum _POOL_TYPE {
  NonPagedPool,
  PagedPool,
  NonPagedPoolMustSucceed,
  DontUseThisType,
  NonPagedPoolCacheAligned,
  PagedPoolCacheAligned,
  NonPagedPoolCacheAlignedMustS
} POOL_TYPE;

这里看起来跟PUSH 1好象没有什么关系,现在看看源代码:

    registryPath.Buffer = ExAllocatePool( PagedPool,
                                          RegistryPath->Length + sizeof(UNICODE_NULL));

这里使用的参数是PagedPool,对于enum类型的定义,每个成员代表的数字是从0开始递增。PagedPool刚好在第二个位置,所以它是1。源代码使用的ExAllocatePool,反汇编后的代码使用的是ExAllocatePoolWithTag。MSDN的说法是ExAllocatePool已经被舍弃了,取代的是ExAllocatePoolWithTag(以标识申请内存)。调用API之后是对返回结果的判断:

    if (!registryPath.Buffer) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

它对应的汇编代码是

.text:000105E5                 mov     edi, eax
.text:000105E7                 xor     ebx, ebx
.text:000105E9                 cmp     edi, ebx
.text:000105EB                 mov     [ebp+Path], edi
.text:000105EE                 jnz     short loc_105FA
.text:000105EE
.text:000105F0                 mov     eax, 0C000009Ah
.text:000105F5                 jmp     loc_1075A

注意到000105F0,STATUS_INSUFFICIENT_RESOURCES=0C000009Ah,仍然使用EAX作为返回参数。接下来的源代码,终于看到编译优化了:

    registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
    registryPath.MaximumLength = registryPath.Length;

    RtlZeroMemory( registryPath.Buffer, registryPath.Length );

    RtlMoveMemory( registryPath.Buffer,  RegistryPath->Buffer,
                   RegistryPath->Length  );

    RtlZeroMemory( ¶mTable[0], sizeof(paramTable));

这里本来要调用2个API的。对于前一个RtlZeroMemory调用,编译器使用自己的代码来代替它:

.text:000105FA                 mov     ax, [esi]
.text:000105FD                 add     ax, 2
.text:00010601                 movzx   ecx, ax
.text:00010604                 mov     edx, ecx
.text:00010606                 xor     eax, eax
.text:00010608                 shr     ecx, 2
.text:0001060B                 rep stosd
.text:0001060D                 mov     ecx, edx
.text:0001060F                 and     ecx, 3
.text:00010612                 rep stosb

先是4字节对齐的填0,然后使用AND取得除以4后的余数,继续填0。第二次调用,编译器同样使用自己的代码来实现这个功能:

.text:00010624                 add     esp, 0Ch
.text:00010627                 xor     eax, eax
.text:00010629                 lea     edi, [ebp+QueryTable]
.text:0001062F                 push    0Eh
.text:00010631                 pop     ecx
.text:00010632                 rep stosd

现在让我们再来看看系统中RtlZeroMemory的代码:

00402520: 57                       PUSH EDI
00402521: 8B7C2408                 MOV EDI, [ESP+08]
00402525: 8B4C240C                 MOV ECX, [ESP+0C]
00402529: 33C0                     XOR EAX, EAX
0040252B: FC                       CLD ;这一句用来保证DF=0
0040252C: 8BD1                     MOV EDX, ECX
0040252E: 83E203                   AND EDX, 00000003
00402531: C1E902                   SHR ECX, 02
00402534: F3AB                     REP STOSD
00402536: 0BCA                     OR ECX, EDX
00402538: 7504                     JNZ 40253E;非4字节对齐,继续填0
0040253A: 5F                       POP EDI
0040253B: C20800                   RETN 0008
0040253E: F3AA                     REP STOSB
00402540: 5F                       POP EDI
00402541: C20800                   RETN 0008

高级语言似乎不提供修改标志寄存器的功能,CLD可以省掉。在编译过程中比较需要填0的内存是否4字节对齐,把比较语句也省了。这里的代码没有以函数的形式出现,当然连传递参数和保存环境的代码也省了。至于RtlMoveMemory,编译器用下面代码代替:

.text:00010614                 movzx   eax, word ptr [esi]
.text:00010617                 push    eax             ; size_t
.text:00010618                 push    dword ptr [esi+4] ; void *
.text:0001061B                 push    [ebp+Path]      ; void *
.text:0001061E                 call    ds:memmove

选择使用MEMMOVE而不是RtlMoveMemory。简单分析了一下,前者为每种情况都准备了一个独立的处理例程,通过跳转表的形式来实现,后者则是使用了不少比较命令。由于代码量较多,有兴趣的可以自己看看。
编译出来的程序,至少在代码段,看起来跟RING 3没有什么区别,同样可以通过程序实现的功能和驱动导入表,估计程序用了什么API,下断,并最终定位目标功能代码。我们需要做的事,只是熟悉这些API和一些常用的RING0机制,然后就可以象分析RING 3程序一样分析RING 0了。下面我将把重点放在API的解释。程序下一个调用的API是RtlQueryRegistryValues,MSDN可以查得该函数的功能是访问注册表。其中一个参数的结构如下:

typedef struct _RTL_QUERY_REGISTRY_TABLE {
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG Flags;
    PWSTR Name;
    PVOID EntryContext;
    ULONG DefaultType;
    PVOID DefaultData;
    ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;

关于Flags标记,可用的常量如下:

RTL_QUERY_REGISTRY_SUBKEY
RTL_QUERY_REGISTRY_TOPKEY
RTL_QUERY_REGISTRY_REQUIRED
RTL_QUERY_REGISTRY_NOVALUE
RTL_QUERY_REGISTRY_NOEXPAND
RTL_QUERY_REGISTRY_DIRECT
RTL_QUERY_REGISTRY_DELETE

对于这类型常量定义,从1(二进制)开始,第二个是10(二进制),第三个是100(二进制),如此类推。源代码中使用的是RTL_QUERY_REGISTRY_DIRECT,所以有如下代码:

.text:0001064F                 mov     [ebp+QueryTable.Flags], 20h

这里有点想不明白,在此API调用之前的大段代码和几个API的调用,都是为了初始化此API的Path参数。为什么不能直接使用入口参数RegistryPath的BUFFER,而要另外分配内存,转移数据在作为传入参数?另外在此API的注释中看到这一句话“The table must be allocated from nonpaged pool.”。程序没有申请一块nonpaged内存存放QueryTable结构,而是直接使用堆栈。难道RING 0下的堆栈都是nonpaged的?此外程序此后并没有对该API的返回值或者返回数据作任何处理。这里大胆假设一下到目前为止的代码都是垃圾代码。另外我注意到编译器的对于每行代码几乎都是很机械的编译,下面源代码:

    paramTable[0].EntryContext = &startType;
    paramTable[0].DefaultType = REG_DWORD;
    paramTable[0].DefaultData = &startType;

对应的反汇编代码:

.text:00010634                 lea     eax, [ebp+var_4]
.text:00010637                 push    4
.text:00010639                 mov     [ebp+QueryTable.EntryContext], eax
.text:0001063C                 lea     eax, [ebp+var_4]
.text:0001063F                 pop     edi
.text:00010640                 mov     [ebp+QueryTable.DefaultData], eax

编译器将相同的赋值语句归类了,但是却对EAX重复赋值,显然0001063C处的代码可以省略。接下来是ZwOpenKey。根据NTSTATUS的定义(详见WINDDK中的ntstatus.h),最高位有如下定义:

//          00 ? Success                        ;对应的16进制最高位0
//          01 ? Informational                ;4
//          10 ? Warning                        ;8
//          11 ? Error                                ;c

比较是否成功调用的代码是:

.text:0001069D                 test    eax, eax
.text:0001069F                 jl      short loc_106CF;最高位为1(调用失败),跳

在RING 3下API调用失败返回的是-1,NATIVE API则是以返回值的最高位来判断调用是否成功。

.text:00010675                 lea     eax, [ebp+Handle]
.text:00010678                 push    20006h          ; DesiredAccess
.text:0001067D                 push    eax             ; KeyHandle
.text:0001067E                 mov     [ebp+ObjectAttributes.RootDirectory], ebx
.text:00010681                 mov     [ebp+ObjectAttributes.Attributes], 40h
.text:00010688                 mov     [ebp+ObjectAttributes.ObjectName], esi
.text:0001068B                 mov     [ebp+ObjectAttributes.SecurityDescriptor], ebx
.text:0001068E                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], ebx
.text:00010691                 call    ds:ZwOpenKey

由上面代码可知,该API的KeyHandle参数,使用的就是DriverEntry的第二个参数。也就是说KeyHandle其实就是一个UNICODE_STRING结构。搞不懂micro$oft,一样的东西搞这么多概念干什么。另外想不明白的是,假如该API调用成功,将会在注册表写入一些数据。但是对程序的运行没有影响。ZwOpenKey调用失败了反而省了几行代码。随后是IoCreateDevice和IoCreateSymbolicLink建立驱动对象和符号连接,API调用失败则把建立的对象和符号连接删除。为IRP_MJ_SHUTDOWN,IRP_MJ_CREATE,IRP_MJ_CLOSE和IRP_MJ_DEVICE_CONTROL分派处理例程。分别有下面对应关系:

       名称                                                描述                                        调用的API
IRP_MJ_CREATE                       请求一个句柄                                             CreateFile
IRP_MJ_CLOSE                             关闭句柄                                         CloseHandle
IRP_MJ_DEVICE_CONTROL        控制操作(利用IOCTL宏)        DeviceIoControl
IRP_MJ_SHUTDOWN                   系统关闭                                InitiateSystemShutdown

当RING 3程序调用上述API对驱动进行操作时,系统会查找该IRP对应的处理例程地址,并调用该例程。

.text:0001071B                 mov     eax, offset sub_104B4
.text:00010720                 cmp     edi, ebx
.text:00010722                 mov     [esi+70h], eax
.text:00010725                 mov     [esi+40h], eax
.text:00010728                 mov     [esi+38h], eax
.text:0001072B                 mov     [esi+78h], eax

此处ESI指向的是DriverEntry的第一个参数DriverObject。+38h是IRP_MJ_CREATE,+40h是IRP_MJ_CLOSE。具体请查阅WINDDK中的wdm.h。

.text:0001074E                 mov     eax, ds:KeServiceDescriptorTable
.text:00010753                 mov     dword_1080C, eax

执行完这两行代码,把SSDT存到全局变量中便结束了DriverEntry例程,也就是说驱动的初始化完毕了。实现驱动功能的代码在IRP例程中,这让我想起RING 3下的消息环。下面来看看sub_104B4:

.text:000104B4 sub_104B4       proc near               ; DATA XREF: start+187 o
.text:000104B4                                                                        ;按照IRPDispatch例程的定义
.text:000104B4 arg_0           = dword ptr  8                        ;DeviceObject
.text:000104B4 arg_4           = dword ptr  0Ch                ;pIrp

关于pIrp结构,MSDN中的定义不完整。对照源代码可知:

+0ch                DWORD                AssociatedIrp.SystemBuffer
+18h          DWORD                IoStatus.Status
+1Ch          DWORD                IoStatus.Information
+3ch                DWORD                UserBuffer
+60h                DWORD                irpStack

irpStack:

+00h                BYTE                MajorFunction ,查询WINDDK中的WDM.h可知

#define IRP_MJ_CREATE                            0x00
#define IRP_MJ_CLOSE                            0x02
#define IRP_MJ_DEVICE_CONTROL           0x0e
#define IRP_MJ_SHUTDOWN                 0x10

+04h                DWORD                Parameters.DeviceIoControl.OutputBufferLength
+08h                DWORD                Parameters.DeviceIoControl.InputBufferLength
+0ch                DWORD                Parameters.DeviceIoControl.IoControlCode
+18h                DWORD                FileObject

该函数根据不同的IRP消息,进入不同的流程。其中从IRP_MJ_DEVICE_CONTROL的处理流程可知,当IoControlCode的低3位为111(二进制,即METHOD_NEITHER)时,驱动程序使用UserBuffer返回数据,反之则使用SystemBuffer。现在来看看sub_103DA,即是源代码中的HDHookDeviceControl函数:

.text:000103EB                 cmp     ecx, 83050000h
.text:000103F1                 jz      loc_104A7
.text:000103F1
.text:000103F7                 cmp     ecx, 83050004h
.text:000103FD                 jz      loc_104A0
.text:000103FD
.text:00010403                 cmp     ecx, 83050008h
.text:00010409                 jz      short loc_1047E
.text:00010409
.text:0001040B                 cmp     ecx, 8305000Ch
.text:00010411                 jz      short loc_10452
.text:00010411
.text:00010413                 cmp     ecx, 83050010h
.text:00010419                 jz      short loc_10426

函数将IoControlCode保存在ECX中,经过对比跳转到相关代码中。在用户态程序中,通过下面API与驱动进行通信:

BOOL DeviceIoControl(

    HANDLE hDevice,        // handle to device of interest
    DWORD dwIoControlCode,        // control code of operation to perform
    LPVOID lpInBuffer,        // pointer to buffer to supply input data
    DWORD nInBufferSize,        // size of input buffer
    LPVOID lpOutBuffer,        // pointer to buffer to receive output data
    DWORD nOutBufferSize,        // size of output buffer
    LPDWORD lpBytesReturned,        // pointer to variable to receive output byte count
    LPOVERLAPPED lpOverlapped         // pointer to overlapped structure for asynchronous operation
   );

也就是说,拦截该API,取得dwIoControlCode,在IRP分派例程的入口下条件断点。然后便可以定位驱动中相关的功能代码。我想看到这里,大家都大概了解RING 0的一些机制,并且能尝试动态调试一些程序了。该程序大部分代码的功能Rockhard在他的贴里已经讲得很清楚了,除了如何取得系统调用号。我们知道系统调用号随着系统版本,甚至SP之间也会有所不同,如何兼容各版本?我对此很感兴趣,先看看源代码:

VOID HookStart( void )
{
    if( !IsHooked ) {
        RealZwDeviceIoControlFile = SYSCALL( ZwDeviceIoControlFile );
        SYSCALL( ZwDeviceIoControlFile ) = (PVOID) HookZwDeviceIoControlFile;
        IsHooked = TRUE;
    }
}

你能想象这样的代码能取得ZwDeviceIoControlFile在SSDT中的位置吗?现在再让我们看看反汇编代码:

.text:00010381                 mov     eax, ds:ZwDeviceIoControlFile
.text:00010386                 mov     ecx, ssdt
.text:0001038C                 push    esi
.text:0001038D                 mov     edx, [eax+1];这里有点奇怪,取函数的机械码?
.text:00010390                 mov     esi, [ecx]
.text:00010392                 mov     edx, [esi+edx*4]
.text:00010395                 pop     esi
.text:00010396                 mov     dword_10814, edx
.text:0001039C                 mov     eax, [eax+1]
.text:0001039F                 mov     ecx, [ecx]
.text:000103A1                 mov     dword ptr [ecx+eax*4], offset sub_1030E

现在让我们来看看ZwDeviceIoControlFile的代码:

00400BC6: B838000000               MOV EAX, 00000038
00400BCB: 8D542404                 LEA EDX, [ESP+04]
00400BCF: CD2E                     INT 2E
00400BD1: C22800                   RETN 0028

入口点加1,便是系统调用号。最后感谢所有看到这里的人

[课程]Android-CTF解题方法汇总!

收藏
免费 7
支持
分享
最新回复 (53)
雪    币: 263
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
2
看不懂
2006-12-6 21:44
0
雪    币: 338
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
不懂.学习一下!
一口气写了这么多.真的不容易!!
2006-12-6 21:45
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
4
昨天开始写的。时间充足,对R0有兴趣的人可以看看,主要就是解释了一些最基本的机制,以及如何查阅MSDN和WINDDK中的头文件得出想要的常量。当然实在查不出,就只有用WINDDK自己写个程序出来反汇编看看了。

看完这文章再看双机调试的文章,相信可以开始尝试玩驱动壳了。不过我暂时是没时间的。学校本科评估,学生受罪。明天又要开始强化实验了。
2006-12-6 21:55
0
雪    币: 263
活跃值: (10)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
5
一直已来都很佩服楼主
2006-12-6 22:23
0
雪    币: 267
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
Good Job
2006-12-6 22:23
0
雪    币: 222
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
好文支持,写得很认真啊。想问一下楼主是哪个学校的,顺便指出两个个人认为不太正确的地方

“从逆向的角度来看,象这种静态字符变量,如果换成全局变量,或者可以获得更高的运行效率和更小的程序”

我想一般还是称为静态常量比较合适吧

“在RING 3下API调用失败返回的是-1”

失败通常返回0,成功返回非0
2006-12-6 22:25
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
8
%检查一个寄存器的值是否为-1%

    因为许多Ring-3 API会返回你一个-1(0FFFFFFFFh)值,如果函数失败的话,而且当你比较它是否失败的时候,你必须对那个值进行比较。

引用自WIN 32病毒教程。这是我接触汇编时看的第一个教程,毕竟是比较早期的,可能现在不是这样吧。我9月份才学逆向,分析的程序有限,也超过3年没接触编程了,我以前学过VB。

的确称为常量比较适合。

我是广州的,学校名字叫广州大学。每年都有评估,我的一个网友,上海的,也评估。。。也是实验排满了,占用课余时间。
2006-12-6 22:48
0
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
帅!!!!!!!!!!!
2006-12-7 00:02
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
10
学习学习,,,近来也搞SYS的驱动东东.(文件过滤驱动的东东)
经常用0环的东东.资料在说又少捏...不得不逆推原理厄.
貌似象Free Build环境.
支持...
2006-12-7 08:41
0
雪    币: 383
活跃值: (41)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
11
不敢看~~~完全不懂的说
2006-12-7 08:51
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
12
最初由 qiweixue 发布
学习学习,,,近来也搞SYS的驱动东东.(文件过滤驱动的东东)
经常用0环的东东.资料在说又少捏...不得不逆推原理厄.
貌似象Free Build环境.
支持...


IFSDDK里面有一些定义。然后啊拉下载DOSKEY上存的驱动资料里面有文件过滤驱动的资料,不知道你看过没有。
2006-12-7 08:57
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
13
最初由 笨笨雄 发布
IFSDDK里面有一些定义。然后啊拉下载DOSKEY上存的驱动资料里面有文件过滤驱动的资料,不知道你看过没有。

谢谢.笨笨雄  
DDK2003 IFS for xp都装了捏...
IFS中的文件过滤sfilter例子正在学习之中...
偶菜捏...刚入门捏...
只能创建一个过滤控制设备对象...Dispath Function和FastIO Rontine.偶正在学习捏...
2006-12-7 09:34
0
雪    币: 222
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
14
Filter Driver的话,先看简单硬件的(键盘、鼠标这类)比较好
2006-12-7 09:54
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
15
最初由 笨笨雄 发布
%检查一个寄存器的值是否为-1%

因为许多Ring-3 API会返回你一个-1(0FFFFFFFFh)值,如果函数失败的话,而且当你比较它是否失败的时候,你必须对那个值进行比较。

引用自WIN 32病毒教程。这是我接触汇编时看的第一个教程,毕竟是比较早期的,可能现在不是这样吧。我9月份才学逆向,分析的程序有限,也超过3年没接触编程了,我以前学过VB。
........


呵呵,原来是校友啊!高兴ING
2006-12-7 09:56
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
ring0就是驱动层的东西吗?
不如说剖析一个驱动入口过程更确切点。
文章写的不错。虽然有些地方还可以再充实一点。一些细节的确有些遗漏。
2006-12-7 10:47
0
雪    币: 163
活跃值: (60)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
17
有驱动编写的基础,再去逆向驱动代码,比逆向应用层的程序要简单得多,现在驱动加壳的不多,而且相对代码量比较小
2006-12-7 10:52
0
雪    币: 452
活跃值: (72)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
18
最初由 老Y 发布
现在驱动加壳的不多

以后会多起来的
2006-12-7 11:00
0
雪    币: 163
活跃值: (60)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
19
不一定会多, 主要不是技术问题,过两年vista成熟起来以后,驱动合法加载是个问题
2006-12-7 11:10
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
20
最初由 冷血书生 发布
呵呵,原来是校友啊!高兴ING


不会吧。。。

19楼说的那个技术听说过了,不会是真的吧?

那M$不是更加垄断了?我电脑不知道用的什么硬件,都是没有经过M$认证的
2006-12-7 12:38
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
21
最初由 笨笨雄 发布
不会吧。。。


19楼说的那个技术听说过了,不会是真的吧?

........


是啊!!!你在大学城那边吧?

我家离那不远! 我那学校跟大学城就像邻居!
2006-12-7 13:44
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
22
最初由 冷血书生 发布
是啊!!!你在大学城那边吧?

我家离那不远! 我那学校跟大学城就像邻居!


汗。。。那你什么学校?

大学城附近还有大学?

你还是学生?
2006-12-7 13:51
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
23
最初由 笨笨雄 发布
.text:00010381 mov eax, ds:ZwDeviceIoControlFile
.text:00010386 mov ecx, ssdt
.text:0001038C push esi
.text:0001038D mov edx, [eax+1];这里有点奇怪,取函数的机械码?
.text:00010390 mov esi, [ecx]
.text:00010392 mov edx, [esi+edx*4]
.text:00010395 pop esi
.text:00010396 mov dword_10814, edx
.text:0001039C mov eax, [eax+1]
.text:0001039F mov ecx, [ecx]
.text:000103A1 mov dword ptr [ecx+eax*4], offset sub_1030E

mov     edx, [eax+1];这是取出对应系统服务表的Dispath ID号.在这里就是对应取出:ZwDeviceIoControlFile 的ID号.我xp os pack2 它的ID号为:42.
内核根据这个Dispath ID和KeServiceDescriptorTable表基地址计算出ZwDeviceIoControlFile在服务表中的入口指针.
mov     esi, [ecx]-->取KeServiceDescriptorTable给si
mov     edx, [esi+edx*4]-->计算出ZwDeviceIoControlFile在服务表的指针,然后把ZwDeviceIoControlFile入口地址给edx,因为驱动要hook服务表之前要保存一下.
mov     dword ptr [ecx+eax*4], offset  sub_1030E--->hook指向自己的MyZwDeviceIoControlFile函数....

2006-12-7 16:28
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
24
谢谢楼上的详细解释,不过我在最后已经给出了解释了
2006-12-7 16:51
0
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
25
最初由 笨笨雄 发布
汗。。。那你什么学校?

大学城附近还有大学?

你还是学生?


当然有,至少有那么一间,挂名广州大学,不过今年起,就改名了,我们好像属于广州大学的最后一批专科生了!不是学生了,现在家摆地摊!
:)工作实在难找!
2006-12-7 19:58
0
游客
登录 | 注册 方可回帖
返回
//