??xml version="1.0" encoding="utf-8" standalone="yes"?>
忘了操作pȝ会根据处理器型号加蝲不同版本内核?...
正好看到高端调试上有关于q个的讨? http://advdbg.org/forums/2142/ShowPost.aspx
但是我的分析是基于ntoskrnl的,没办法,只好强制指定pȝ加蝲ntosknrl?得做以下几个工作
1 把vm的processor调成单核单处理器
2 开windows虚拟? Z告诉pȝ现在是单核单处理器模?得跑一下这个命?nbsp;rundll32.exe setupapi,InstallHinfSection ACPIAPIC_UP_HAL 131 %windir%\inf\hal.inf
参? 如何修改Windows XPpȝ的内核类?nbsp; http://blog.sina.com.cn/s/blog_5918846401000bik.html
3 当然,q里q没l束,如果处理器支持PAE 那么pȝ会加载ntoskrnla 所以还得禁用PAE. ?span style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 30px; background-color: #ffffff;">BOOT.INI里面, 启动讄中如果有/noexecute=optin替换改?execute,没有的话加?/span>/execute
完了后就会加载ntoskrnl?效果?
指定其它pȝҎcM,在此仅抛砖引?nbsp;
]]>
C++标准规定:
~译器的cȝcd转换对空指针(NULL)Ҏ处理,即你NULLq行强制cd转化的结果还是NULL,所以?
static_castcd转化的时?_ATL_PACKING的值得是非零就?/code>
C++ Standard 4.10/3 Pointer conversions [conv.ptr]:
An rvalue of type “pointer to cv D,?where D is a class type, can be converted to an rvalue of type “pointer to cv B,?where B is a base class (clause 10) of D. If B is an inaccessible (clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion is a pointer to the base class sub-object of the derived class object. The null pointer value is converted to the null pointer value of the destination type.
此文会涉及到一些普通堆的知识,q些内容可以参见我之前的文章 WINDBG的堆调试--了解HEAPl织
所谓的堆破坏,是说没控制好自己的指针,把不属于你分配的那块内存l写覆盖了。这块内存可能是你程序的数据Q也可能是堆的管理结构。那么这个会D怎样的后果呢Q可能的情况我们来yy?/font>
堆破坏较为理想的情况是被修改的数据会马上DE序crashQ最差的情况是你的堆数据莫名其妙在今天被改了Q但明天才crash。这个时候在d析crashQ就如我们的警察叔叔现在接手一?0q前的案子一?---无从下手。老外UC为heap corruption是很贴切的,有时候咱堆数据被意外改是无声无息的Q你也许没法从界面甚x志文件中看到它被改的一点迹象,当到某一个时刻,q种错误会暴露出来,然而这个时候查看堆信息也许会是毫无头A。所以对于堆破坏Q咱的策略是早发现我们的堆被篡改了Q最好能够在堆数据被意外改的那一时刻诱发一个异常来提醒我们----兄弟Q你的堆被腐蚀了?/font>
微Y提供了一些方案,来帮助我们诊断堆破坏。一般来_堆破坏往往都是写数据越界造成的(yy的第二种情况Q如果是W一U情况其实还单,下个内存断点好Q,所以微软在堆分配上Q给E序员门额外提供?U堆分配模式--完全堆Qfull page heapQ,准页?normal page heap)Q用来检堆被写界的情c?/font>
完全堆的检基本思\是通过分配盔R的一个页Qƈ其设ؓ不可讉K属性,然后用户数据块会被分配到内存늚最末端Q从而实现越界访问的。当我们对堆中分配的内存d界后便会访问到那个不可ȝ,pȝ捕获到改ơ异常后会试图中断执行ƈ该异常上报ldebuggerQ或者崩溃。具体的内存l织l构如下?/font>
摘自《Y件调试?/font>
与普通堆不同的是Q内存块前面的HEAP_ENTRYl构被DPH_BLOCK_INFORMATIONl构取代Q这个结构内部记录了堆模式下这个内存块的一些基本信息。如果用h据区前面的数据,也就是DPH_BLOCK_INFORMATIONl构被破坏了Q那么在释放内存块的时候系l会报错Q如果编E者对q块内存块读写越界了Q当Ӟq里界有几U情况:
q里需要注意的q是块尾填充不一定存?/font>Q块֡充是因ؓ要满_内存的最分配粒度,如果本n内存块的分配_度已l是最分配粒度的倍数了,那么块尾填充׃存在了,比如堆内存分配粒度是? bytesQ那么如果申请了14 bytes的话会有2 bytes的大徐小的块֡充块Q如果申请了24bytesQ那么就没有块尾填充了,因ؓ24正好?的倍数?/font>
开启全堆Q用windbg目录下的gflags或者装一个appverifier都可以开启)Q通过自己写的一个heap.exe来看一下如何用全堆堆破坏情况heap.exe代码如下Q?/font>
#include "windows.h" int main() { HANDLE heap_handle = HeapCreate( NULL , 1024 , 0 ) ; char *temp = NULL ; char *buffer = (char*)HeapAlloc(heap_handle , NULL , 128) ; char *buffer1 = (char*)HeapAlloc(heap_handle , NULL , 121) ; temp = buffer ; for( int i = 0 ; i < 138 ; ++i ) { *(temp++) = 'a' ; } HeapFree(heap_handle, 0 , buffer ) ; HeapFree(heap_handle, 0 , buffer1 ) ; HeapDestroy( heap_handle) ; return 0 ; }
在第14行向buffer写入138字节Q这昄界了,然后在用windbg启动heap.exeQ直接运行,会发现报错如?/font>
0:000> g
(1f50.1f54): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000080 ebx=00000000 ecx=02596000 edx=02596000 esi=00000001 edi=00193374
eip=00191068 esp=0016fdc8 ebp=0016fddc iopl=0 nv up ei ng nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010297
heap!main+0x68:
00191068 c60161 mov byte ptr [ecx],61h ds:0023:02596000=??
报了一个内存访问错误,然后看一下调用堆?/font>
0:000> kb
ChildEBP RetAddr Args to Child
0016fddc 0019120f 00000001 023fbfd0 0239df48 heap!main+0x68 [d:\projects\heap\main.cpp @ 14]
0016fe20 765b1114 7ffd3000 0016fe6c 778eb429 heap!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 582]
0016fe2c 778eb429 7ffd3000 757369d8 00000000 kernel32!BaseThreadInitThunk+0xe
0016fe6c 778eb3fc 00191357 7ffd3000 00000000 ntdll!__RtlUserThreadStart+0x70
0016fe84 00000000 00191357 7ffd3000 00000000 ntdll!_RtlUserThreadStart+0x1b
可以看到是第14行报的错Q但?4行的代码q行了那么多ơ,我们再看一下这个时候变量i的值是多少
0:000> dv i
i = 0n128
昄Q在填充W?28字节的时候,我们的temp指针讉KC栅栏,从而报Z一个内存违规的异常?/font>
q里带看一下如果我们分配的内存不是8 bytes的情况(一般堆内存分配_度? bytesQ所以申?28 bytes的内存时是不会有块尾填充部分的)
那我们接下来看另外一D代?/font>
我们把第10行的temp = bufferҎtemp = buffer1
因ؓbuffer1甌?21 bytesQ也是说它? bytes的填充字?/font>
0:000> g
(1ba0.1ba4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000080 ebx=00000000 ecx=024c8000 edx=024c8000 esi=00000001 edi=00033374
eip=00031068 esp=002cfb80 ebp=002cfb94 iopl=0 nv up ei ng nz ac pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010297
heap!main+0x68:
00031068 c60161 mov byte ptr [ecx],61h ds:0023:024c8000=??
0:000> dv i
i = 0n128
可以看到变量iq是128Q也是说我们还是在讉K到第128字节后才引发讉K异常Q而不是我们期望的121字节后就引发异常?/font>
q里也就是说如果我们的代码中对申L堆内存写界了,写数据覆盖块֡充部分的时候ƈ不会引发异常Q?/font>
但是Q这q不代表我们的写界问题不会被发现。块֡充部分是会被填充上固定数据的Q系l在适合的时机(比如销毁堆的时候)会校验块֡充块Q如果发现块֡充块数据有变Q那么便会报一个verifier异常Q比如我们把代码中的for循环ơ数改ؓ124
for( int i = 0 ; i < 124 ; ++i )
那么windbg会中断在W?9?/font>
HeapDestroy( heap_handle) ;
提示内容如下
=======================================
VERIFIER STOP 0000000F: pid 0x1E3C: Corrupted suffix pattern for heap block.
025A1000 : Heap handle used in the call.
025A7F80 : Heap block involved in the operation.
00000079 : Size of the heap block.
025A7FF9 : Corruption address.
=======================================
This verifier stop is not continuable. Process will be terminated
when you use the `go' debugger command.
=======================================
(1e3c.143c): Break instruction exception - code 80000003 (first chance)
eax=6c75e994 ebx=6c75cf58 ecx=00000002 edx=002bf461 esi=00000000 edi=000001ff
eip=6c753c38 esp=002bf6b4 ebp=002bf8b8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
vrfcore!VerifierStopMessageEx+0x543:
6c753c38 cc int 3
提示说的很清楚了Qappverifier指出了堆和具体的内存块,我们q个时候查看buffer1的值是0x025a7f80 Q正好就是出问题的堆块,出问题的地址?x025a7ff79Q正好就是buffer1内存块的边界Q错误原因是Corrupted suffix pattern for heap blockQ也是说咱块尾填充部分Qsuffix pattern for heap blockQ被破坏QcorruptedQ了
l论Q只要写界Q系l都能够出来,只不q如果写界写到了栅栏页会理解触发异怸断,而写界只写了块֡充部分,那么pȝ在适当时机Q比如堆被销毁,或者这块内存被重新分配{时机)会对块尾填充部分做完整性检,如果发现被破坏了Q就会报错。当Ӟ你可以根据错误号Q?font color="#0000ff">蓝色字体部分Q信息去appverifier的帮助文档中查找更详l的错误说明?/font>
q次咱来倒叙Q先从最基本的内存堆块结构DPH_BLOCK_INFORMATION开始介l,DPH_BLOCK_INFORMATIONl构微Y也有对应文档介绍
其中prefix start magic和prefix end magic是校验块Q用来检DPH_BLOCK_INFORMATION是否被破坏,q些部分属于DPH_BLOCK_INFORMATIONl构。我们先来用windbg探究下DPH_BLOCK_INFORMATIONq个最基本的结?再一?我们打开windbg调试heap.exe.q行到第10?q个时候变量的值是
0:000> dv heap_handle
heap_handle = 0x024a0000
0:000> dv buffer
buffer = 0x024a5f80 "???"
0:000> dv buffer1
buffer1 = 0x024a7f80 "???"
q里可以看到一个很有趣的现?buffer1和buffer的地址正好相差8K,也就是两个页的大?q当然是因ؓ堆的原因啦,其实q两块内存分配是盔R着?虚拟内存l构如下图所C?/font>
buffer内存块(4KQ?/font> | 栅栏(4KQ?/font> | buffer1内存?4K) | 栅栏?4K) |
׃buffer和buffer1分配的大是一LQbuffer1加上N填充块和buffer的大相同)Q所以这两块内存正好相差8K
而DPH_BLOCK_INFORMATION在我们甌的内存块指针的前0x20字节处,用dt命o看的l果如下:
0:000> dt _DPH_BLOCK_INFORMATION 0x024a5f80-0x20
verifier!_DPH_BLOCK_INFORMATION
+0x000 StartStamp : 0xabcdbbbb
+0x004 Heap : 0x024a1000 Void
+0x008 RequestedSize : 0x80
+0x00c ActualSize : 0x1000
+0x010 Internal : _DPH_BLOCK_INTERNAL_INFORMATION
+0x018 StackTrace : 0x003d9854 Void
+0x01c EndStamp : 0xdcbabbbb
0x024a5f80-0x20是DPH_BLOCK_INFORMATIONl构的地址。DPH_BLOCK_INFORMATIONl构在已分配和已释放的状态下QStartStamp和EndStampQ也是MSDN图中的prefix start magic和prefix end magicQ是不同的,昄dt输出的结果看来,q个内存块是已分配状态。StackTrace记录了分配这个内存块时的调用栈,可以用dds来看一下这个内存块被分配时候的调用?/font>
0:000> dds 0x003d9854
003d9854 00000000
003d9858 00004001
003d985c 00090000
003d9860 5b3b8e89 verifier!AVrfDebugPageHeapAllocate+0x229
003d9864 776d5c4e ntdll!RtlDebugAllocateHeap+0x30
003d9868 77697e5e ntdll!RtlpAllocateHeap+0xc4
003d986c 776634df ntdll!RtlAllocateHeap+0x23a
003d9870 003b1030 heap!main+0x30 [d:\projects\heap\main.cpp @ 8]
003d9874 003b120c heap!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 582]
003d9878 76451114 kernel32!BaseThreadInitThunk+0xe
003d987c 7766b429 ntdll!__RtlUserThreadStart+0x70
003d9880 7766b3fc ntdll!_RtlUserThreadStart+0x1b
输出l果我们可以看到q个内存块是在main.cpp,也就是我们的CZ代码的第8行分配的Q第8行是char *buffer = (char*)HeapAlloc(heap_handle , NULL , 128) 正好是分配buffer内存的那条语句。这个结构的其它字段Q顾名思义QActualSize指明了实际分配字节数Q?x1000 bytes也就?K大小QInternalq个字段保存了个内部l构Q用windbg也看不出q个l构信息?/font>
当然Z防止内存块前面的数据被冲hQ除了DPH_BLOCK_INFORMATION外,pȝq通过DPH_HEAP_BLOCK保存了所分配内存块的信息Q?/font>
通过!heap –p –h [address] 可以查看到页堆的信息
0:000> !heap -p -h 0x024a0000 //heap_handle的?/font>
_DPH_HEAP_ROOT @ 24a1000
Freed and decommitted blocks
DPH_HEAP_BLOCK : VirtAddr VirtSize
Busy allocations
DPH_HEAP_BLOCK : UserAddr UserSize - VirtAddr VirtSize
024a1f6c : 024a5f80 00000080 - 024a5000 00002000
024a1f38 : 024a7f80 00000079 - 024a7000 00002000
可以看到Qbuffer内存块对应的DPH_HEAP_BLOCKl构地址?font color="#0000ff">024a1f6c
0:000> dt _DPH_HEAP_BLOCK 024a1f6c
verifier!_DPH_HEAP_BLOCK
+0x000 NextFullPageHeapDelayedNode : 0x024a1020 _DPH_HEAP_BLOCK
+0x004 DelayQueueEntry : _DPH_DELAY_FREE_QUEUE_ENTRY
+0x000 LookasideEntry : _LIST_ENTRY [ 0x24a1020 - 0x0 ]
+0x000 UnusedListEntry : _LIST_ENTRY [ 0x24a1020 - 0x0 ]
+0x000 VirtualListEntry : _LIST_ENTRY [ 0x24a1020 - 0x0 ]
+0x000 FreeListEntry : _LIST_ENTRY [ 0x24a1020 - 0x0 ]
+0x000 TableLinks : _RTL_BALANCED_LINKS
+0x010 pUserAllocation : 0x024a5f80 "???"
+0x014 pVirtualBlock : 0x024a5000 "???"
+0x018 nVirtualBlockSize : 0x2000
+0x01c Flags : _DPH_HEAP_BLOCK_FLAGS
+0x020 nUserRequestedSize : 0x80
+0x024 AdjacencyEntry : _LIST_ENTRY [ 0x24a1f5c - 0x24a1fc4 ]
+0x02c ThreadId : 0x3f4
+0x030 StackTrace : 0x003d9854 Void
从dt的数据看来,q个l构大小?x34Qbuffer和buffer1的DPH_HEAP_BLOCKl构首地址正好也是相差0x34Q说明这两个l构是紧挨着的,下一步在让我们来看看DPH_HEAP_BLOCKl构是如何组l的?/font>
摘自《Y件调试?/font>
q个是整个的堆l构图,我们先来说说DPH_HEAP_BLOCK的组l吧Q在图中0x16d00000是页堆的首地址Q也是堆的句柄,我们调试器中Q页堆首地址则是0x024a0000Qؓ了数据统一Q我q是?x024a0000作ؓ堆句柄来讲解。我们的DPH_HEAP_BLOCK其实在堆块节点池里边,我们可以q似把这个节Ҏ看成一个大型的DPH_HEAP_BLOCK数组Q但有个地方在Y件调试中没有提到Q就是在win7下,q行时这些DPH_HEAP_BLOCKl构都是以二叉^衡数的结构来l织的,q个树的l构的入口正是在TableLinks字段内,q么做的原因也大概是因ؓ能够在分配时更快的烦。我们再看看DPH_HEAP_ROOTl构Q这个结构储存了整个堆的必要信息,它就相当于普通堆的_HEAPl构?/font>
0:000> dt _dph_heap_root 24a1000
verifier!_DPH_HEAP_ROOT
+0x000 Signature : 0xffeeddcc
+0x004 HeapFlags : 0x1002
+0x008 HeapCritSect : 0x024a16cc _RTL_CRITICAL_SECTION
+0x00c NodesCount : 0x2c
+0x010 VirtualStorageList : _LIST_ENTRY [ 0x24a1fa0 - 0x24a1fa0 ]
+0x018 VirtualStorageCount : 1
+0x01c PoolReservedLimit : 0x024a5000 Void
+0x020 BusyNodesTable : _RTL_AVL_TABLE
+0x058 NodeToAllocate : (null)
+0x05c nBusyAllocations : 2
+0x060 nBusyAllocationBytesCommitted : 0x4000
+0x064 pFreeAllocationListHead : (null)
+0x068 FullPageHeapDelayedListTail : (null)
+0x06c DelayFreeQueueHead : (null)
+0x070 DelayFreeQueueTail : (null)
+0x074 DelayFreeCount : 0
+0x078 LookasideList : _LIST_ENTRY [ 0x24a1078 - 0x24a1078 ]
+0x080 LookasideCount : 0
+0x084 UnusedNodeList : _LIST_ENTRY [ 0x24a1ed0 - 0x24a16e4 ]
+0x08c UnusedNodeCount : 0x28
+0x090 nBusyAllocationBytesAccessible : 0x2000
+0x094 GeneralizedFreeList : _LIST_ENTRY [ 0x24a1f04 - 0x24a1f04 ]
+0x09c FreeCount : 1
+0x0a0 PoolCommitLimit : 0x024a2000 Void
+0x0a4 NextHeap : _LIST_ENTRY [ 0x5b3e9a58 - 0x23a10a4 ]
+0x0ac ExtraFlags : 3
+0x0b0 Seed : 0xfed6f13a
+0x0b4 NormalHeap : 0x027d0000 Void
+0x0b8 CreateStackTrace : 0x003d9824 _RTL_TRACE_BLOCK
+0x0bc ThreadInHeap : (null)
+0x0c0 BusyListHead : _LIST_ENTRY [ 0x24a10c0 - 0x24a10c0 ]
+0x0c8 SpecializedFreeList : [64] _LIST_ENTRY [ 0x24a10c8 - 0x24a10c8 ]
+0x2c8 DelayFreeListLookup : [257] (null)
+0x6cc HeapCritSectionStorage : _RTL_CRITICAL_SECTION
q里边维护了很多q行时信息,比如说DPH_BLOCK_INFORMATION中的那个二叉树入口其实就是保存在BusyNodesTable 字段Q这里面记录了所有被分配了的内存块所对应的DPH_BLOCK_INFORMATION。当Ӟq里面一些信息Y件调试里面都有介l,很多看名字也能够猜到大概意思,看名字猜不到啥意思的字段Q其实我也猜不到。。?_-|||在创建页堆后Q所有内存分配都分配在页堆中Q通过分配的地址也能看得出来Q我们分配的内存都是024a打头Q,而非普通页堆中Q普通页堆也仅仅只是保存一些系l内部用的数据。一般来_堆块节点池加上DPH_HEAP_ROOTl构大小正好?个内存页Q也是16K?/font>
对于调试堆破坏来_其实我们只要了解DPH_BLOCK_INFORMATIONl构和DPH_HEAP_BLOCK中的基本字段差不多了,q样更方便我们定位出错源头。比如在appverifier报错后(或者你E序自己莫名其妙崩溃或者数据被改后,要知道appverifierq不L可信的)Q我们可以自己手动调试出错的堆块l构QDPH_BLOCK_INFORMATIONQDPH_HEAP_BLOCK和DPH_HEAP_ROOTQ,以下这些点Q?/font>
其实堆q好Q它有较强的实时性,所以ƈ不需要太多手工调试的操作Q越界读写都会立卌发异常ƈ且中断,所以从q点看来Q它是一些Y件用来检堆资源是否正确使用的必备良药~ 但是相对于页堆,准页堆的调试则需要更好的M解准堆工作原理了,因ؓ它提供的堆块不是实时的Q所以发现问题后Q需要咱“精湛的调试内功“去扑և源头Q关于准堆的东西,下回再说吧,敬请期待~
和大学时不一P我的代码q不会马马虎虎赶完去参加比赛后就弃之不理了,qƈ不是一ơ性代码,它需要维护,更需要体现其价倹{优化完了一个功能,甚至不能说出它比以前好在哪里Q也没有数据可量化,更要命的是我p么让q项目过MQ花?个月做出来的东西Qƈ没有M人知道,也没M人去xQ没有Q何测试数据来说明我让q个功能有了很大E度上的q展。就像以前对凝聚的娃儿们说的Q写出来的Y件没人用Q不用到的技术再_湛Q也是堆废代码。切记切讎ͼ不论如何Q要量化自己的工作,有数据的Ҏ别h才知道是q步?/p>
从来到公司到现在Q终于知道什么叫出期望了。as一个合格程序员Q你得按时完成老大布置的Q务。但事情q远不止q些Q老大很多时候只是给你指明方向,q不会告诉你每一步怎么赎ͼq样做的好处能够让你自由发挥Q坏处是Ҏq。这也许是好多新来时候的通病Q被z指d后无从下手。这个可是个沟通的z,首先必须要精了解老大的预期,CQ我q里说的是精了解,当然老大的预期ƈ不一定完全正,但是Q在你没法辩驳用数据辩驳他不正确的时候,你要做的是攉资料Q然后分析可行性,再然后给老大复述你的计划Q在我看来,我其实ƈ不希望我的计划和老大的预惛_全一_更多的讨论才会生一个完的ҎQ如果你仅仅只是按老大说的dQ那么就是那个qualified programmerQ一定一定要CQ你最好得有自q观点Q观点必d撞Q碰撞中才会反思各放观点的优劣Q一个权衡的观点才会出来。其实需求确认这一步可能很多h看来很冗余,但是在我看来很是必需Q因为口口相传的需求ƈ不会_到哪里去Q所以需要确认确认再认Q省的做完后又得打翻重做?/p>
技术的事情Q千万别p涂Q你的程序crash了,你得知道为啥Q你的newp|了,你也得知道ؓ啥,因ؓ随着E序来大Q你debug的难度会来高Q有问题Q早解决Q而且Ҏ有问题,你必ȝ其所以然。当Ӟ那些恶心的没有文档而且注释只注释了一半的W三方库除外Q用q种库还不如自己重新写一个去Q一直认U成品的存在是个鸡肋。编E里面有一句话叫donot repeat yourselfQ你得管理好q且ȝ你的代码QL一天,你或者别能用得到?/p>
q是我最大的一个毛病了吧,其实攑֜互联|公司这U催q度好比催命般的大环境下Q这是坏习惯,我工作模式一般是串行化且关中断模式,一件事必须得先做完才开始做下一件事情,中间容不得有M注意力的转移。但是往往中间会有更加重要的事情插播进来,当然Q如果出现这U情况那是项目管理上的悲哀Q但事实如此Q等待现状改变还不如去适应。清楚的知道优先U,q其实非帔R要的Q因为很有可能插播进来的d兌到其他同事,处理不好Q会出现目发布前N个h{你的这U状况,说难听点Q这时候你成了后腿,重点是别人怎么拖也拖不动?/p>
说好的每周一ơ运动在工作三个月后q消云散了Q我是那U做事情的时候容易走火入的E序员,事情没解决之前脑子里全部都是相关的事情,但往往q样是最没有效率的,反倒去q动q动Q待W二天脑袋清C反倒就有结果了Q老天喃。。。我关中断的思维模式何时能{q来。。。程序员应该是最最需要锻炼的体了吧Q一天坐10个小时还不带上厕所的,可以遇见好多人在几年后都会脊椎等地方开始出毛病Q但q是我们可以遇见得到的啊。。。竟焉知道了,Z不去L其发生呢Q不为别人,单是Z现在或者未来的家hQ好好爱护自qw体比Q何事情都重要Q期待有一个hQ,Q,能在我走火入之际把我拉出来L一场球Q以前有妖Q有番薯Q有葡萄哥,而现在呢Q没有你们的城市里我也要健康的活着Q不为别的,只ؓ留着口气把赚来的钱好好的花出?nbsp; -_-#Q指不定哪天我暴毙了银行里还有好几百万,q丫的不亏大了?/p>
暂时p么多吧,希望q些能在我今后半q有所改善Q也许在我看来,技术已l不再是全部Q做事情的方式才是我今后惛_前辈学习的地斏V?/p>
写驱动的时候有个地方老是蓝屏,看了dump发现数据被非法篡改了.
数据初始化如?/p>
if(record_set_ptr != NULL )
{
record_set_ptr->look_aside_pool_ptr = g_user_control_context.look_aside_pools[type] ;
record_set_ptr->type = type ;
record_set_ptr->buffer_size = notify_count * unit_size_of ;
record_set_ptr->units_count = notify_count ;
record_set_ptr->complete_count = 0 ;
}
然后在调用ExFreeToNPagedLookasideList传入record_set_ptr->look_aside_pool_ptr 的时候挂?发现record_set_ptr->look_aside_pool_ptr已经被改?
Z跟踪数据在哪里被修改?先在数据初始化的地方下断,然后Crecord_set_ptr->look_aside_pool_ptr 的地址:0x85c16018
对这个内存下个断?
1: kd> ba w4 85c16018
w表示在写入时断下,4表示监控范围,单位是字?nbsp;
整个命o的意思就是让调试器在pȝ写入内存85c16018-85c1601bq个地址范围的时候中?
OK,命o下完,F5一下就立马断下来了
1: kd> g
Breakpoint 3 hit
nt!memcpy+0x33:
8053b583 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
此时edi的? 0x85c16018
最后看一下函数堆?发现是字W串拯界覆盖了后面的数据....
后面又想?出错时record_set_ptr->look_aside_pool_ptr 的值是0x005c0065
q么明显的字W串特征竟然没意识到....一看出错值就应该知道是字W串覆盖造成?....
堆栈堆栈Q在操作pȝ内存中有两种存储I间Q一个是堆,一个是栈。堆主要用于存储用户动态分配的变量Q而栈呢,则是存储我们E序q程中的临时变量。当然栈的作用远不止用作存储变量Q但q不是我们这文章的讨论内容?/p>
堆(HEAPQ的分配Q用,回收都是通过微Y的API来管理的Q最常见的API是malloc和new。在往底层C点呢Q这两个函数都会调用HeapAllocQRtlAllocateHeapQ。同L相关函数q有HeapFree用来释放堆,HeapCreate用来创徏自己的私有堆。下面是q些函数的调用链Q?/p>
HeapCreate->RtlCreateHeap->ZwAllocateVirtualMemory (q里会直接申请一大片内存,至于甌多大内存,pEPEBl构中的字段觉得QHeapSegmentReserve字段指出要申请多大的虚拟内存QHeapSegmentCommit指明要提交多大内存,对虚拟内存的甌和提交概念不清楚的童鞋,请参见windows核心~程相关内容~)
HeapAlloc->RtlAllocateHeapQ至于这里申L内存Q由于HeapCreate已经甌了一大片内存Q堆理器这片内存中划分一块出来以满甌的需要。这一步申h作是堆管理器自己l护的,仅当甌内存不够的时候才会再ơ调用ZwAllocateVirtualMemory Q?/p>
HeapFree->RtlFreeHeap Q对于释攄内存Q堆理器只是简单的把这块内存标志位已释放让后加入到I闲列表中,仅当I闲的内存达C定阀值的时候会调用ZwFreeVirtualMeMory Q?/p>
HeapDestroy->RtlDestroyHeap->ZwFreeVirtualMeMory Q销毁我们申L堆)
WINDBG观察?/p>
源码Q?/p>
#include "windows.h" int main() { HANDLE heap_handle = HeapCreate( NULL , 0x1000 , 0x2000 ) ; char *buffer = (char*)HeapAlloc(heap_handle , NULL , 128) ; char *buffer1 = (char*)HeapAlloc(heap_handle , NULL , 121) ; HeapFree(heap_handle, 0 , buffer ) ; HeapFree(heap_handle, 0 , buffer1 ) ; HeapDestroy( heap_handle) ; return 0 ; }
该源码生成编译生成heap.exeQ然后用windbg调试q个E序Q在main函数下断Q紧接着执行W五行语句,执行l果如下
0:000> p
eax=002e1ca0 ebx=00000000 ecx=6d29b6f0 edx=00000000 esi=00000001 edi=01033374
eip=01031012 esp=0022fe8c ebp=0022feac iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
heap!main+0x12:
01031012 ff150c200301 call dword ptr [heap!_imp__HeapCreate (0103200c)] ds:0023:0103200c={kernel32!HeapCreateStub (769a29d7)}
0:000> p
eax=002c0000 ebx=00000000 ecx=77429897 edx=77498500 esi=00000001 edi=01033374
eip=01031018 esp=0022fe98 ebp=0022feac iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
heap!main+0x18:
01031018 8945fc mov dword ptr [ebp-4],eax ss:0023:0022fea8=6d222201
0:000> !heap
Index Address Name Debugging options enabled
1: 00300000
2: 00010000
3: 00020000
4: 002e0000
5: 002c0000
HeapCreate执行的返回值存攑֜eax处,q个函数q回了一个堆句柄Q?x002c0000。用!heap命o查看可以看到W五个堆是我们创徏的堆句柄了?/p>
每个q程都存在多个堆Q我们也可以通过PEBl构来得到进E中存在的堆Q结果和!heap命o昄的内Ҏ一L?/p>
heap!_PEB
+0x018 ProcessHeap : 0x00300000 Void ; q程的默认堆
+0x068 NtGlobalFlag : 0 ; q个标志位记录了当前堆调试模?0为普通调试模?br /> +0x078 HeapSegmentReserve : 0x100000 ; q程在新建堆的时候默认申L虚拟内存大小
+0x07c HeapSegmentCommit : 0x2000 ; q程在每ơ申h交的虚拟内存大小Q在提交的内存用完后Q进E会又在一ơ提交HeapSegmentCommit中指定的内存大小
+0x080 HeapDeCommitTotalFreeThreshold : 0x10000 ; 当释攄内存大小大于q个阀|p行内存解除提交操?br /> +0x084 HeapDeCommitFreeBlockThreshold : 0x1000 ; 当一ơ性释攄块大超q这个阀|p行内存解除提交操作,只有当满两个条g时才会调用ZwFreeVirtualMeMory 释放物理内存
+0x088 NumberOfHeaps : 5 ; 当前q程的堆数目,q个数目对应着!heap命o的堆昄个数
+0x08c MaximumNumberOfHeaps : 0x10 ; q程所能运行的最大堆数目,若堆数目过q个g计HeapCreate失败了?br /> +0x090 ProcessHeaps : 0x77498500 -> 0x00300000 Void ;存储堆句柄的数组,q里我们可以得到q程的所有堆句柄
我们可以输入如下命o来查看现有的堆句?/p>
0:000> dd 0x77498500
77498500 00300000 00010000 00020000 002e0000
77498510 002c0000 00000000 00000000 00000000
77498520 00000000 00000000 00000000 00000000
77498530 00000000 00000000 00000000 00000000
77498540 00000000 77498340 7749bb08 77498220
77498550 00000000 00000000 00000000 00000000
77498560 77498220 00317bd0 00000000 00000000
77498570 00000000 00000000 00000000 00000000
可以看得到这里面的内容和!heap命o的输出结果是一L
而堆句柄的存放范?从MaximumNumberOfHeaps 上来?是77498500-77498540q?x40个字节,因ؓ每个堆句柄占4个字节,0x10个堆句柄的存攄间就?x40?/p>
堆的理Q我们可以理解ؓ一个内存池Q它甌一大块I间Q然后负责接应用程序的甌释放{请求。只有在创徏堆,释放堆(注意Q是释放堆,不是堆中的空_Q在q之前,我们需要对堆有关的数据l构做一些解?/p>
我这里观察到的HEAPl构QHEAP_SEGMENTl构和HEAP_ENTRYl构都和软g调试里面描述的不一P当年奎哥写Y件调试的时候估计还没用上WIN7吧。。。我的演C系l是WIN7
HeapCreate函数q回的堆句柄其实是一个指向堆理l构的指针,每个堆都会涉及到q样三个l构QHEAP,HEAP_SEGMENT,HEAP_ENTRY
HEAP_ENTRYl构Q?/p>
在堆理中,每一块申请下来的内存都会有下面所C的固定模式Q?/p>
HEAP_ENTRYQ? bytesQ?/p> |
我们new或malloc分配的空?/p> |
固定填充I间 |
q个l构用来记录所分配的空间的信息Q包括用LLI间Q填充的I间Q所在的D号{等信息。所以我们new或者malloc的地址减去8指向该l构。第三部分的固定填充I间是ؓ了内存对齐而生成的Q当然这部分I间q有一部分是用来额外记录这块内存的其它信息Q这里就不详l做介绍了?/p>
HEAP_SEGMENTl构Q?/p>
我们可以q么认ؓQ堆甌内存的大是以段为单位的Q当新徏一个堆的时候,pȝ会默认ؓq个堆分配一个段?hQ通过刚开始的new和malloc分配的空间都是在q个D上分配的,当这个段用完的时候,如果当初创徏堆的时候指明了HEAP_GROWABLEq个标志Q那么系l会个堆在再分配一个段Q这个时候新分配的段q?h了,以下以此cL。每个段的开始初便是HEAP_SEGMENTl构的首地址Q由于这个结构也是申L一块内存,所以它前面也会有个HEAP_ENTRYl构Q?/p>
HEAP_ENTRYQ? bytesQ?/p> |
HEAP_SEGMENT |
HEAP_ENTRYQ? bytesQ?/p> |
我们new或malloc分配的空?/p> |
固定填充I间 |
HEAP_SEGMENTl构会记录段的一些基本信息,该段甌的大,已经提交内存的大,W一个HEAP_ENTRYl构的入口点。(我观察看貌似D는L内存q不会一ơ性全部提交,而是每次提交一个页的大,比如一个段大小2个页Q那么它会先提交一个页内存Q若用完了再提交一个页的内存,若内存还用完了那新Z个段Q这个新建的D也会是先提交一个页内存。)但是0h很特别,q个D늚起始地址是堆句柄指针指向的|也就是说Q?/font>HeapCreateq回的堆句柄L指向0hQؓ什么呢Q因为HEAPl构是HEAP_ENTRY,HEAP_SEGMENT的合体加长版~
HEAPl构Q?/p>
HEAPl构则是记录了这个堆的信息,q个l构可以扑ֈHEAP_SEGMENT链表入口Q空闲内存链表的入口Q内存分配粒度等{信息。HEAP的首地址便是堆句柄的|但是堆句柄的值又?h的首地址也是堆句柄,何解Q其实很单,0h的HEAP_SEGMENT在HEAPl构里面QHEAPl构cd义如q样Q?/p>
struct _HEAP { _HEAP_ENTRY Entry ; //HEAP_ENTRYl构Q用来描q存储HEAP内存块大等信息? _HEAP_SEGMENT Segment ; //0h的首地址 …? //对于该HEAP的描qC? } ;
在我们看来,内存l织l构应该如下所C:
HEAP_ENTRYQ? bytesQ?/p> |
HEAP_SEGMENT |
HEAP |
更确切的_HEAPl构中本w就包含了HEAP_ENTRY和HEAP_SEGMENTQHEAP_ENTRYl构是HEAP的第一个数据成员,HEAP_SEGMENT是它W二个数据成员。而对于HEAP_SEGMENT,它的W一个数据成员便是HEAP_ENTRY。这里ؓ了方便理解,才在内存l织l构中把它们拆开展示。(注:q里是win7的情况,和Y件调试这本书中所描述的有一些差异,也属正常现象Q毕竟这部分l构微Yq未公开Q?/p>
在之前已l演CZ如何从PEBl构中找到所有的堆句柄,可以看到002c0000便是我们创徏的句柄。然后我们执CZE序的第7行代码。执行完后结果如下:
0:000> p
eax=002c0000 ebx=00000000 ecx=77429897 edx=77498500 esi=00000001 edi=01033374
eip=01031026 esp=0022fe8c ebp=0022feac iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
heap!main+0x26:
01031026 ff1500200301 call dword ptr [heap!_imp__HeapAlloc (01032000)] ds:0023:01032000={ntdll!RtlAllocateHeap (774120b5)}
0:000> p
eax=002c0590 ebx=00000000 ecx=774134b4 edx=002c0180 esi=00000001 edi=01033374
eip=0103102c esp=0022fe98 ebp=0022feac iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
heap!main+0x2c:
0103102c 8945f0 mov dword ptr [ebp-10h],eax ss:0023:0022fe9c={heap!envp (0103301c)}
可以看到EAX保存的返回gؓ002c0590。我们通过两种途径来观察我们申L内存Q通过!heap命o观察和通过dt命o观察
输入命o!heap –a 2c0590得到的结果如下:
0:000> !heap -a 2c0000
Index Address Name Debugging options enabled
5: 002c0000
Segment at 002c0000 to 002c2000 (00001000 bytes committed)
Flags: 00001000
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 0000013a
Max. Allocation Size: 7ffdefff
Lock Variable at: 002c0138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 002c00a0
Uncommitted ranges: 002c0090
002c1000: 00001000 (4096 bytes)
FreeList[ 00 ] at 002c00c4: 002c0618 . 002c0618
002c0610: 00088 . 009d0 [100] - free
Segment00 at 002c0000:
Flags: 00000000
Base: 002c0000
First Entry: 002c0588
Last Entry: 002c2000
Total Pages: 00000002
Total UnCommit: 00000001
Largest UnCommit:00000000
UnCommitted Ranges: (1)
Heap entries for Segment00 in Heap 002c0000
002c0000: 00000 . 00588 [101] - busy (587)
002c0588: 00588 . 00088 [101] - busy (80)
002c0610: 00088 . 009d0 [100]
002c0fe0: 009d0 . 00020 [111] - busy (1d)
002c1000: 00001000 - uncommitted bytes.
q个命o分别提炼ZHEAPQ绿色区域),HEAP_SEGMENTQ红色区域)和HEAP_ENTRYQ灰色区域)l构中的信息。虽然在灰色区域中,我们找不?c0590Q但是找C一?c0588Q这个正?c0590-8的结果,也就是说最双的地址是每个HEAP_ENTRY的首地址Q接着00588q个字段表示了前面一个HEAP_ENTRY所占用的大,后面?088表示q个内存块的d,x们申L内存+HEAP_ENTRYQ?28+8=0x80+0x8=0x88Q,[101]是这块内存的标志位,最双一位ؓ1表示该内存块被占用。然后busyQ?0Q就是解释说q块内存是被占用的(非空闲的Q,它申L内存?x80Q{化成十进制正好就是我们申L128字节大小?/p>
但是q里用dt _HEAP_ENTRY 2c0588命o却没办法查看对应的结构信息,真是怪哉Q有博文也提到win2008中HEAP相关l构也有变,看来到NT6后,HEAPl构变得不小Qv码windbg中直接dt HEAP_ENTRY是无法原始数据的了,貌似对HEAP_ENTRY做了~码?/font>
同样的,已知HEAP的首地址Q那么先从HEAP下手好了Qdt _HEAP 002c0000可以昄HEAP的数据结?/p>
ntdll!_HEAP
+0x000 Entry : _HEAP_ENTRY
+0x008 SegmentSignature : 0xffeeffee
+0x00c SegmentFlags : 0
+0x010 SegmentListEntry : _LIST_ENTRY [ 0x2c00a8 - 0x2c00a8 ]
+0x018 Heap : 0x002c0000 _HEAP
+0x01c BaseAddress : 0x002c0000 Void
+0x020 NumberOfPages : 2
+0x024 FirstEntry : 0x002c0588 _HEAP_ENTRY
+0x028 LastValidEntry : 0x002c2000 _HEAP_ENTRY
+0x02c NumberOfUnCommittedPages : 1
+0x030 NumberOfUnCommittedRanges : 1
+0x034 SegmentAllocatorBackTraceIndex : 0
+0x036 Reserved : 0
+0x038 UCRSegmentList : _LIST_ENTRY [ 0x2c0ff0 - 0x2c0ff0 ]
+0x040 Flags : 0x1000
+0x044 ForceFlags : 0
+0x048 CompatibilityFlags : 0
+0x04c EncodeFlagMask : 0x100000
+0x050 Encoding : _HEAP_ENTRY
+0x058 PointerKey : 0x17c06e63
+0x05c Interceptor : 0
+0x060 VirtualMemoryThreshold : 0xfe00
+0x064 Signature : 0xeeffeeff
+0x068 SegmentReserve : 0x100000
+0x06c SegmentCommit : 0x2000
+0x070 DeCommitFreeBlockThreshold : 0x200
+0x074 DeCommitTotalFreeThreshold : 0x2000
+0x078 TotalFreeSize : 0x13a
+0x07c MaximumAllocationSize : 0x7ffdefff
+0x080 ProcessHeapsListIndex : 5
+0x082 HeaderValidateLength : 0x138
+0x084 HeaderValidateCopy : (null)
+0x088 NextAvailableTagIndex : 0
+0x08a MaximumTagIndex : 0
+0x08c TagEntries : (null)
+0x090 UCRList : _LIST_ENTRY [ 0x2c0fe8 - 0x2c0fe8 ]
+0x098 AlignRound : 0xf
+0x09c AlignMask : 0xfffffff8
+0x0a0 VirtualAllocdBlocks : _LIST_ENTRY [ 0x2c00a0 - 0x2c00a0 ]
+0x0a8 SegmentList : _LIST_ENTRY [ 0x2c0010 - 0x2c0010 ]
+0x0b0 AllocatorBackTraceIndex : 0
+0x0b4 NonDedicatedListLength : 0
+0x0b8 BlocksIndex : 0x002c0150 Void
+0x0bc UCRIndex : (null)
+0x0c0 PseudoTagEntries : (null)
+0x0c4 FreeLists : _LIST_ENTRY [ 0x2c0618 - 0x2c0618 ]
+0x0cc LockVariable : 0x002c0138 _HEAP_LOCK
+0x0d0 CommitRoutine : 0x17c06e63 long +17c06e63
+0x0d4 FrontEndHeap : (null)
+0x0d8 FrontHeapLockCount : 0
+0x0da FrontEndHeapType : 0 ''
+0x0dc Counters : _HEAP_COUNTERS
+0x130 TuningParameters : _HEAP_TUNING_PARAMETERS
如本文前面所q的Q第一个字D|HEAP_ENTRYl构Q接着应该是HEAP_SEGMENTQ这里只不过把HEAP_SEGMENTl构的字D展开了,可以dt _HEAP_SEGMENT来观察下q个l构的字D?/p>
0:000> dt _heap_segment
ntdll!_HEAP_SEGMENT
+0x000 Entry : _HEAP_ENTRY
+0x008 SegmentSignature : Uint4B
+0x00c SegmentFlags : Uint4B
+0x010 SegmentListEntry : _LIST_ENTRY
+0x018 Heap : Ptr32 _HEAP
+0x01c BaseAddress : Ptr32 Void
+0x020 NumberOfPages : Uint4B
+0x024 FirstEntry : Ptr32 _HEAP_ENTRY
+0x028 LastValidEntry : Ptr32 _HEAP_ENTRY
+0x02c NumberOfUnCommittedPages : Uint4B
+0x030 NumberOfUnCommittedRanges : Uint4B
+0x034 SegmentAllocatorBackTraceIndex : Uint2B
+0x036 Reserved : Uint2B
+0x038 UCRSegmentList : _LIST_ENTRY
可以看到HEAPl构中灰色部分是和HEAP_SEGMENTl构中的字段是重复的Q也是说灰色部分字D便是HEAP_SEGMENTl构。在HEAP_SEGMENTl构中,我们可以扑ֈFirstEntry字段Q这里指的便是我们的分配的内存,不过HEAP_ENTRYl构无法观察Q这里便没办法枚丑և所有的HEAP_ENTRYl构了,但是说一下思\Q?/p>
每个HEAP_ENTRY和它对应的内存我们可以称Z个内存块Q计下一个内存块需要用到现有内存块中的2个字D,Size和UnsedBytesQSize的g上粒度(是0:000> !heap -a 2c0000命o昄的信息中的Granularity: 8 bytes字段Q这里是8字节Q,下一个内存块地址是 本内存块地址+Size*8+UnsedBytes。当然这里的_度可以通过HEAP字段中的AlignMask 字段出来?/p>
在HEAPl构中指明了分配_度Q这个分配粒度是说每ơ堆分配的时候,都以q个_度为最单位,q里看到_度?字节。所以这里就有了W二ơ分配内存的实验Q我们让E序执行W?行,然后?heap -a 002c0000观察分配情况
Heap entries for Segment00 in Heap 002c0000
002c0000: 00000 . 00588 [101] - busy (587)
002c0588: 00588 . 00088 [101] - busy (80)
002c0610: 00088 . 00088 [101] - busy (79)
002c0698: 00088 . 00948 [100]
002c0fe0: 00948 . 00020 [111] - busy (1d)
002c1000: 00001000 - uncommitted bytes.
q里可以看出多出了一个占用块Q大是0x79Q?21Q?bytesQ但是实际分配的大小q是0x 88 Q?28QbytesQ这是因为系l是? bytes为粒度分配的Q所以ؓq块121 bytes的内存自动填充了7个字节,可见甌121 bytes和申?28 bytes所使用的空间是一L?/font>
执行?1行和12行的代码后,堆中的内容分别如下:
执行11行代码的堆情?/strong>
FreeList[ 00 ] at 002c00c4: 002c06a0 . 002c0590
002c0588: 00588 . 00088 [100] ?free Q空闲列表中多出了一块内?/font>
002c0698: 00088 . 00948 [100] ?free Q空闲内存,I闲I间?48
执行12行代码的堆情?/strong>
FreeList[ 00 ] at 005c00c4: 005c0590 . 005c0590
005c0588: 00588 . 00a58 [100] ?free Q回收了buffer1的内存后Q由于由于空闲内存是q箋的,所以直接合q成一块内存。可以看C前内存freeI间?48Q现在合q了以后便是948+88+88=a58,也就是当前内存大?/font>
Heap entries for Segment00 in Heap 005c0000
005c0000: 00000 . 00588 [101] - busy (587)
005c0588: 00588 . 00a58 [100]
005c0fe0: 00a58 . 00020 [111] - busy (1d)
005c1000: 00001000 - uncommitted bytes.
最后执?4行代?对堆q行释放,释放后我们通过!heap也可以看到只?个堆?我们甌的堆被释放了.
0:000> !heap
至于HEAP_ENTRYl构的问?有时间在调试看看是怎么回事吧~另外Q这里说明下Qnew和malloc内部都会调用HeapAlloc来申请内存,但是堆句柄从哪来呢?它会_crtheap变量是否为空Q若不ؓI则拿_crtheap变量来作q堆句柄去调用HeapAlloc
参考:
软g调试 张奎?/p>
MSDN
昨天在京东上买的TP-LINK WN821N v3无线|卡Q今天就到手?发货真快~~凌晨l我发来邮g说已送货Q注意查收。。。。汗~~
q个无线|卡是我的开发网卡,׃一下午研究才翻到的一个commview for wifi和aircrack都能使用的网卡,用的atheros的芯片,具体型号可以?a >http://linuxwireless.org/en/users/Drivers/ath9k_htc/devices
q个|址上查到?/p>可惜我的是ubuntu 10.04的版本,不到这个网卡,只能自己动手装了
我这里安装的是ath9k_htc
多亏了下面这两篇文章Q网卡成功在ubuntu上面跑v来了
不过上面说貌似在UBUNTU 11.04中就可以识别出来Q我也不晓得 q个待验证?/p>
试了下aircrack
sudo aircmon start wlan%d Q貌似网卡名解析有错。。。。竟然给我解析成wlan%dQ不q也能用Q将吧~Q?/p>
打开wireshark监听mon0q个虚拟|卡Q结果如?/p>
嘿嘿 可以使用Q那接下来可以lwireless fundamentalpd文章了,noctilioq个开源项目也开始步入开发阶D了
之前写了一文? VIM–指定自qVIM工作目录
今天准备把windows下的vim配置弄到虚拟Z的ubuntu?于是有了这文?仅记录下期间遇到的问?/p>
1. 把windows文gҎ到ubuntu?/p>
我这里是用了vmware tools来搞定的,先安装vmware tools,然后在edit virtual mechine setting中的options里面有个shared floders,把它设ؓalways enable然后在下面添加自p׃n的目录就是了,我在q里面把我之前的$MY_VIM_DIRq个环境变量的目录添加进M,我的floder name为vim.然后在虚拟机的UBUNTU下面,?mnt/hgfs/vim目录下就可以讉K我的vim配置文g?W一步搞?没什么大问题.
2.然后在环境变量中d$MY_VIM_DIR(/mnt/hgfs/vim)?VIMINIT(source $MY_VIM_DIR/_vimrc)环境变量,我这里查了下资料,在~/.bashrcq个文g中加上这两句话:
export MY_VIM_DIR=/mnt/hgfs/vim
export VIMINIT="source $MY_VIM_DIR/_vimrc"
在每ơ启动bash的时候会执行~/.bashrcq个文gQ我们的环境变量p动设q去了,但是q个讄只对当前用户有效Q换个用h们设|的环境变量׃起作用了. 如果你希望对全局用户都有?那么可以M?etc/profile文g,在文件末֊上这两句?
3.好了,一切就l?在控制台启动VIM, p|! 提示说检到有^M, 无法解析.?windows格式~码问题....
解决Ҏ很简?先跑去装个tofrodos,命o: sudo apt-get install tofrodos
然后执行sudo fromdos -p $MY_VIM_DIR/*/*.vim
把配|文件目录下的所?vim文g的换行都转成unix格式?/p>
然后在我们的_vimrc中加入一句话: set fileformat=unix
告诉vim我们换行W用unix格式?/p>
在windows? gvim可以识别q种带有unix换行W的vimrc文g
OK,问题解决
4.执行sudo vim, ?... 竟然没有加蝲我的_vimrc文g,而是转而加载了默认?vimrc文g,也就是说2中设|的环境变量不v作用
然后惛_能是sudo用的是root,不会l承我这个用L环境变量,OK 我在/etc/profile中设|环境变量d以了?/p>
d后登?看效?/p>
?.. q是不行
然后癑ֺ了一?原来在sudo命oZ安全性考虑,执行期间会把环境变量reset,然后保留可信的环境变?比如$PATHq种变量
那么问题扑ֈ好办了,有几U方?/p>
a. 使用sudo -s命oQ指出sudol承shell环境变量
b. 执行visudo命o, 把Defaults env_resetҎDefaults !env_reset?止sudo对环境变量重|,因ؓ我是在虚拟机上个人用ubuntu做开?所以用的这U方?若在多h׃n使用的操作系l上,q是推荐使用aҎ安全?/p>
最q在试用moin wiki来做协同开发,直接用moin自带的编辑器太不爽了Q字体难看不_q没法着Ԍ看着不舒服?/p>
然后L索了下vim中相关moin的插Ӟ想不到还真有Q?/p>
首先是这?a >editmoinQ用python写的Q可以通过q个插g来直接操作moin的页面,但是我这里是windowspȝQ它老读不到我的配置文g。这个方法linux下的用户可以用,我就不行咯,所以作|,重新L其它Ҏ?/p>
然后去moin主页上看Q上面推荐了一个firefox的插Ӟ可以使用指定~辑器来~辑面内容Q插件地址在这Q?a s All Text!
q款插g中你指定vim为编辑器可以了Q然后在~辑的时候激z该插g卛_Q它会帮你把内容复制到vim中,~辑完关闭后会把修改应用到网늼辑器内,很好用的说~~哈哈
此外Q在moin官网上提到的vim插gmoin.vim可以对moin wiki语法q行高亮昄Q但是用的时候注意,hmoin.vim中的 hi clear q一句话注释?否则vim中配|的主题会失?/p>
@AuthorQay @DateQ?011-10-07 @文章出处Q?a >http://cnss-ay.com
@NoticeQ{载请注明作者信息!
在用vim的过E中个,我发现我的vim配置要{Udwindows上很ȝQ因为我的插件和vim插g攑֜vim安装目录下,和vim原配的插件一起了。而且vimrc文g也被我改的很乱,攑ֈwindows上面未必能够直接使用。所以就有了q篇文章Q讨论如何指定的一个自q文g夹,vim从这文g夹中载入我的插g和蝲入初始化文gvimrc?
用过vim的都晓得Qvim在初始化之处会蝲入vimrc文gQ在windows下这个文件是_vimrcQ在linux下是.vimrcQ我们可以修改这个文件来定制我们的初始化操作。但是我们必d把这个vimrc文g攑֜指定的位|才可以被vim到Q这些个路径分别?VIM,$VIMRUNTIME,$HOMEq三个环境变量下所指的路径。这里有两种ҎQ?
1 修改$HOME的\径,把这个环境变量指向我们自己定义的路径Q?VIM?VIMRUNTIME指向的\径可能vimq有其它用途,最好别攏V但是修?HOME也不是很好,特别是linux下,很多E序都是依赖?HOME环境变量的?
2指定$VIMINITQ我是定义了一?MY_VIM_PATH的环境变量,q里面存了我VIM配置文g和插件的目录地址Q然?VIMINIT中的内容是:
source $MY_VIM_PATH/_vimrc
在vim初始化之初会查看$VIMINIT有没有被定义Q若被定义了放弃后面蝲入vimrc的操作,转而执?VIMINIT变量内的操作。当然也可以讄$MYVIMRC的环境变量ؓ$MY_VIM_PATH/_vimrcQvim同样会先载入$MYVIMRC变量中指定的vimrc文g。只有当q两个环境变量都没定义的时候vim才回d下的目录中找vimrc文g?
注:在windows中没法创?vimrc的文Ӟ所以只能用_vimrc代替之?
关于如何讄插gQ帮助文档的查找路径
在vimrc中加入如下语句即?
set runtimepath=$MY_VIM_PATH,$VIMRUNTIME
在vimq行Ӟ会在runtimepath变量中记录的路径中去扑֊载插Ӟ背景色等内容?