初窥win64编程

转自:http://media.ccidnet.com/media/ciw/751/d1001.htm


  从1995年windows 95推出至今,绝大多数windows应用程序都已经从win16平台转移到win32平台,windows 3.x及其代表的16位windows编程技术被迅速打入了冷宫。现在,microsoft公司的软件工程师们针对intel公司的ia-64处理器构架又开始了64位windows编程(win64)技术的设计,由于windows 98是windows 9x系列中的最后一个产品,所以win64将被包含在正在开发的windows nt 5.0中,当intel的新一代64位处理器merced推出后,软件开发人员就可以开始使用64位编程技术,nt的企业计算能力势必会得到极大的提高。

  因为4gb的地址空间满足了目前绝大多数应用的需求,win64与win32之间的差异远小于win32与win16之间的差异,所以win64不会像win32取代win16那样迅速取代win32。在今后相当长的一段时间内,win64将与win32和平共处,相互补充。软件开发人员需要根据应用的特点选择开发平台,或者同时建立应用程序的win64和win32版本,由于win64与win32编程区别不大,在使用高级语言编程时只要遵循一定的原则,花费极少量的时间与精力就可以为不同平台创建相应的版本,并且在多数时候只要对源程序重新编译连接一次就可以了。


  ·llp64抽象数据模型·


  c语言标准中没有规定整型、长整型和指针等变量各有多少位,而是留给了计算平台来确定,因此每种系统及其应用都必须采用某种默认的抽象数据模型来作为计算的基础,win32采用一种称为llp32的模型,即假定整型、长整型和指针变量的字长都是32位,相应定义的int、uint、long、 ulong和handle等数据类型也都是32位,这对于32位windows编程环境来说是合理的规定。如果win64中把整型、长整型和指针变量的字长都改为64位,那么不仅要占有以前两倍的存储空间,而且现有的应用程序及其使用的大多数数据类型都需要作更改,实现两种平台之间的可移植性就变得相当困难了。事实上,在引入64位平台后,应用程序需要实现64位寻址,并只在少数地方需要用到64位数据,而多数时候使用32位数据就足够了,因此,win64采用了一种称为llp64的抽象数据模型,除了把指针变量扩展到了64位外,整型和长整型变量等基本数据类型仍然保持32位。由于基本数据类型都保持32位不变,所以存储在磁盘上的数据不用改变其结构和大小,远程或本地进程之间的共享数据(如内存映射文件)也不用改变其结构和大小,这就大大减轻了程序员的工作量。

  为了实现同一份源代码既能在win32下运行,也能在win64下运行,定义llp64模型只是走出了第一步,接下来还要定义一些与指针相关的数据类型,如对指针进行计算时需要的数据类型等,编译器会根据目标平台来确定这些数据类型是32位还是64位。这些新的数据类型是用c语言的int和long类型定义的,因此保持了对win32及部分windows api函数的向后兼容性,microsoft计划在windows nt 5.0的beta 2版包含这些新数据类型,并逐渐移植所有的windows api函数到64位平台,程序员在nt 5.0 beta 2版及相应的platform sdk推出后就可以开始使用这些数据类型了,当64位平台正式推出后,所编写的程序多数只需重新编译连接一次即可生成64位版本。


  ·新的数据类型·


  新数据类型共有三类:固定精度数据类型(fixed-precision data types)、指针精度数据类型(pointer-precision data type)和指定精度指针(specific-precision pointers)。

  1.固定精度数据类型在win32和win64中有相同的字长,为了便于记忆,它们的名字中包含了其字长。

  ·int32和int64:字长分别为32位和64位的有符号整型数;

  ·long32和long64:字长分别为32位和64位的有符号长整型数;

  ·uint32和uint64:字长分别为32位和64位的无符号整型数;

  ·ulong32和ulong64:字长分别为32位和64位的无符号长整型数。

  2.指针精度数据类型与目标平台的指针的字长相同(由编译器来确定),这样可以把指针安全地转换成指针精度数据类型来进行代数运算和位运算,而不用编程时处处考虑目标平台的类型。

  ·int-ptr和uint-ptr:指针精度的有符号和无符号整型数,win32下字长为32位,win64下字长为64位;

  ·ssize-t和size-t:指针精度的计数器,用于确定指针精度数据类型的字长,前者为有符号计数器。

  3.特定精度指针在win32和win64中都保持相同的字长,因此只在某些特殊情况下才有用。

  ·-ptr64(64位指针):在win32中,32位指针通过符号扩展生成一个64位指针,扩展的结果可能没有任何意义,不能再当做指针来使用;

  ·-ptr32(32位指针):在win64中,64位指针通过截去高32位生成一个32位指针,结果可能没有任何意义,也不能再当做指针来使用。

  使用这些新的数据类型可以更清晰地显示出程序中哪些地方进行的计算实质上与指针相关,这样在进行类型转换时就不容易出错,而win32中原来定义的数据类型就没有这个优点,因此新数据类型有利于我们编写出更健壮的代码,并且为将来移植到64位平台做好了准备。


  ·辅助开发工具·


  在win64下编程与在win32下编程区别很小,因为大家熟悉的windows api函数除了涉及到指针的参数的类型可能改变外,其他没有什么更多的变化,程序员原有的知识仍然有用。为了帮助程序员修改现有的源代码,转而使用新的数据类型,microsoft将在nt 5.0 beta 2版中包含一些开发辅助工具,其中包括一个定义新数据类型的头文件basetsd.h和一个语法检查器。语法检查器可以检查出源程序中不正确的类型转换、指针截断及其他一些与64位相关的问题。例如它会指出下面的代码存在着4311号指针截断警告:

  buff = (puchar)srbcontrol;

  (ulong)buffer += srbcontrol->headerlength;

  为了消除警告,应该把ulong改为uint-ptr,这样才能保证这段代码既能在win32上运行,也能在win64上运行。程序员的目标是消除所有语法检查器发出的警告,尤其是4311号指针截断警告。


  ·编程规则·


  为了顺利实现两种平台的源代码级可移植性,程序员应按照以下规则来编写程序或者修改已有程序。

  1.不能将指针转换成int、uint、long、ulong、dword等字长固定为32位的类型,如果需要对指针做运算,应把指针转换为 int-ptr或uint-ptr,这两种类型在不同平台上才有正确的字长。另外,由于handle实质上是一个指针(void *),因此把handle转换成long或ulong等类型也是不正确的。

  2.如果确定需要对指针进行截断,那么应使用ptrtolong()和ptrtoulong()两个函数(在basetsd.h中定义)来进行,它们可以屏蔽掉指针截断警告,不过截断的结果不能够再当指针使用了。

  3.当某个api函数的out参数能返回一个指针时,应小心谨慎处理参数,在win32中,可以把一个ulong变量的地址进行强制转换后传递给 api函数,返回的指针就保存在ulong变量中,但在win64中,返回的指针有64位,如果使用ulong变量的话就会破坏其他变量的内容,正确并且简单的方法是直接定义一个指针变量,把指针变量的地址作为参数传递给api函数。

  4.谨慎处理多态参数。在win32中,一个函数可以用一个dword参数来接受多态参数,即该参数在不同情况下可能具有不同的意义,如解释成整型数或指针。在win64中,如果一个多态参数可能被解释成指针,那么决不能把多态参数设为dword类型,而应设为uint-ptr或pvoid类型。 win32自身的一部分api函数(如raiseexception())因为不符合该条规则而需要进行修改。

  5.使用新的get/setwindowlongptr和get/setclasslongptr api函数。如果在窗口或类的数据区中存放了指针,就需要调用上面的函数来存取相应的变量,为了帮助程序员在编程中正确处理这一点,头文件 winuser.h把索引值gwl-wndproc、gwl-hinstance、gwl-hwdparent和gwl_userdata的定义取消了,转而定义了新的索引值gwlp-wndproc、gwlp-hinstance、gwlp-hwdparent和gwlp-userdata。这样下面的代码将会引起编译错误:

  setwindowlong(hwnd,gwl-wndproc,(long)mywndproc);

  因为gw-wndproc没有定义,正确的代码应为:

  setwindowlongptr(hwnd,gwlp-wndproc,(int-ptr)mywndproc);

  6.许多窗口和类的数据结构中包含了指针,因此不能在代码中强行指定偏移量来访问数据成员,而应使用field-offset宏来计算偏移量。

  7.由于lparam、wparam和lresult通常用来存放指针或整数,在win64中它们全部被扩展成为64位,因此不能把它们与 dword、ulong、uint、int、int和long等类型混用,否则可能会无意识地把它们截短了。

  关于在win64环境下编程还需要注意的其他问题,以及win64平台下api函数的变化及新增函数,有兴趣的读者可到microsoft的web站点查阅相关资料,或者参考最新版的platform sdk及msdn oline library。

详细目录如下: 0.基础的基础 |-学习WIN64驱动开发的硬件准备 |-配置驱动开发环境 ------------------------------ 1.驱动级HelloWorld |-配置驱动测试环境 |-编译和加载内核HelloWorld ------------------------------ 2.内核编程基础 |-WIN64内核编程的基本规则 |-驱动程序与应用程序通信 |-内核里使用内存 |-内核里操作字符串 |-内核里操作文件 |-内核里操作注册表 |-内核里操作进线程 |-驱动里的其它常用代码 ------------------------------ 3.内核HOOK与UNHOOK |-系统调用、WOW64与兼容模式 |-编程实现突破WIN7的PatchGuard |-系统服务描述表结构详解 |-SSDT HOOK和UNHOOK |-SHADOW SSDT HOOK和UNHOOK |-INLINE HOOK和UNHOOK ------------------------------ 4.无HOOK监控技术 |-无HOOK监控进线程启动和退出 |-无HOOK监控模块加载 |-无HOOK监控注册表操作 |-无HOOK监控文件操作 |-无HOOK监控进线程句柄操作 |-使用对象回调监视文件访问 |-无HOOK监控网络访问 |-无HOOK监视修改时间 ------------------------------ 5.零散内容 |-驱动里实现内嵌汇编 |-DKOM隐藏进程+保护进程 |-枚举和隐藏内核模块 |-强制结束进程 |-强制读写进程内存 |-枚举消息钩子 |-强制解锁文件 |-步探索PE32+格式文件 ------------------------------ 6.用户态HOOK与UNHOOK |-RING3注射DLL到系统进程 |-RING3的INLINE HOOK和UNHOOK |-RING3的EAT HOOK和IAT HOOK ------------------------------ 7.反回调 |-枚举与删除创建进线程回调 |-枚举与删除加载映像回调 |-枚举与删除注册表回调 |-枚举与对抗MiniFilter |-枚举与删除对象回调
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值