查看文章 |
最近又在看恶心的代码,于是在地铁上想了想windows驱动编程的规范问题。整理了一下,如下,欢迎指正和补充。 1 驱动编程中,代码的规范性比技巧更重要。除非有苛刻的要求,否则少用晦涩的技巧。 2 永远要努力将复杂的问题简单化,不要让代码的逻辑不清晰使问题变得更复杂。代码只有自己能看懂那是垃圾,代码可以让更多的人更轻易看懂才叫真正的高 4 项目中涉及到的核心数据结构要提前规划好。涉及到通信的结构要具有可扩展性。 5 算法要符合实际应用,请先拿到可信的测试数据再决定采用何种算法。比如数据量小的时候可以使用list,数据量大了可能有必要使用hash将list进行散列。 6 永远使用最新的ddk版本,使用和OS对应的编译环境编译代码 7 驱动程序需要通过driver verifier测试 8 代码需要在oacr 下无警告 9 所有可以用API搞定的事情请使用API 10 所有对api的使用,请确保通读msdn对该api的描述。 11 所有接受参数的函数,请在函数入口检查参数合法性。所有使用到不可控参数的地方应该用SEH保护起来。 12 如果局部变量作为指针传递出去,请确保调用关系在同一堆栈中。因为局部变量具有挥发性。 13 仅在单个函数内使用的非挥发性变量,请使用static修饰符,避免使用过多的全局变量 14 对于传入传出型参数,请保证仅在函数返回成功的时候修改参数。 15 内核中一个线程的堆栈空间有限,要避免定义过长的局部变量。不使用递归函数。 16 函数尽可能的单出口,不要随地都是return。 17 避免使用goto 18 对于确定类型的指针请不要使用pvoid,因为传入了错误的指针编译器不会报警。 19 所有对指针的指针的使用,请尽量使用引用,除非你非常谨慎。因为传入一级指针编译器还是不会报警。 20 定义结构的时候需要考虑字节对齐的粒度问题。尤其当代码需要在32位和64为下同时使用的时候。 21 对指针做运算时,请注意运算的单位是指针所指数据结构的大小。 22 如果代码想同时适用32,64位平台。需要注意对指针的定义,可以使用PVOID,PULONG_PTR等自动适应的指针类型。 23 所以对buffer的操作,请时刻注意其边界。 24 所有对字符串的操作,请至少使用安全字符串函数。 25 wcscpy之类的c运行时函数操作的字符串必须以0结尾。但是内核中普遍使用的UNICODE_STRING 不能保证这一点。所以不要使用wcsxxx去操作unicode_string。 27 在没有特殊要求的情况下,请使用分页内存。如果使用非分页内存,请尽快释放。 28 避免将代码执行时的IRQL提升到APC_LEVEL 之上,比如在DISPATCH_LEVEL上不能访问分页内存,很多API 不能使用。 29 对于频繁分配,释放的,且小的内存片,请使用LookasideList。 30 对同一资源的释放最好只在一个地方进行,避免重复释放。 31 如果需要在DISPATCH_LEVEL上访问分页内存,必须使用MDL将内存锁定 32 代码停留在DPC level 上的时间要很短。换句话说,dpc上执行的代码要很精练,否则会对系统性能有明显影响。 33 对共享资源的访问要加同步,互斥等机制。注意有些内核分发器对象可以递归获取,有的不能。递归获取的需要递归释放。 34 一条指令就可以对共享数据进行的修改,在单核机器上是安全的。但是请记住未来是多核世界,请使用Interlocked...机制,确保多核平台下操作的原子性。 35 API使用中,如果涉及到权限申请的问题,请保证使用可用的最小权限。 36 仅在内核中使用的句柄,请指定OBJ_KERNEL_HANDLE属性。 37 在内核中使用native api,请使用Zw...,不要直接调用Nt... 38 功能比较明确,且代码不多的时候,请使用宏或者inline函数 39 代码中要避免直接使用数字,请定义成宏 42 每次发布2进制文件,请保存对应的pdb和source。可以用批处理来实现自动化 43 过滤型驱动的完成函数执行时,所在的进程上下文,所在的irql 都是未定义的。 44 避免使用硬编码,如果用到了,请检查平台的版本。对于不支持的平台版本需要bypass 45 如果驱动中设置了任何callback函数,请在驱动卸载前取消对callback的注册。 46 hook型驱动,驱动卸载前必须恢复hook。 47 推荐使用预编译头文件,将各模块共用的东西放这里。 48 强制类型转化时,请注意可能存在的数据被截短情况 49 测试性代码,请用 // for debug, // for test 之类的注释,并尽量整体的放到花括号里面,方便删除 50 过滤驱动,hook型驱动,总之做中间处理的,需要尽可能不修改系统原有的流程。比如异步的过程被改成同步的,并行的被改成串行可能会降低系统性能。 51 hook型驱动,调用任何函数之前,请确保被调用函数内部不会再call到hook函数。否则引发重入。 52 驱动中可以对一些功能模块做开关,方便用排除法解决bug。 |

