Hash长度扩展攻击

引子

大家可以去我的新博客地址:http://blog.leej.me

大家可以去我的新博客地址:http://blog.leej.me

大家可以去我的新博客地址:http://blog.leej.me

无意中碰到一道题,大概代码是这样的

  1. $flag = "XXXXXXXXXXXXXXXXXXXXXXX";
  2. $secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
  3. $username = $_POST["username"];
  4. $password = $_POST["password"];
  5. if (!empty($_COOKIE["getmein"])) {
  6. if (urldecode($username) === "admin" && urldecode($password) != "admin") {
  7. if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
  8. echo "Congratulations! You are a registered user.\n";
  9. die ("The flag is ". $flag);
  10. }
  11. else {
  12. die ("Your cookies don't match up! STOP HACKING THIS SITE.");
  13. }
  14. }
  15. else {
  16. die ("You are not an admin! LEAVE.");
  17. }
  18. }
  19. setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
  20. if (empty($_COOKIE["source"])) {
  21. setcookie("source", 0, time() + (60 * 60 * 24 * 7));
  22. }
  23. else {
  24. if ($_COOKIE["source"] != 0) {
  25. echo ""; // This source code is outputted here
  26. }
  27. }

这个核心的判断在第二个if的判断

if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password)))

也就是需要构造getmein的cookie和他那串字符相同就可以,但是问题是这个$secret的变量我们根本不知道啊

网上找了些关于MD5的资料,发现MD5是存在Hash长度扩展攻击的

MD5算法

MD5的算法比较简单,大概加密过程来看就是类似下图!

首先是数据填充:首先要知道的是,md5后面运算过程都是需要512比特为一组来进行运算,先说一下简单的数据比较少 不存在分组的时候的填充,首先512比特的末尾64比特是存放原明文消息的长度,512比特开始是明文数据紧接着明文后填一位1(2进制),其余全是0,假设我明文就一个字符串‘test’那么填充就是0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

最后四字节也就是2000000000000000代表前面'test'的长度

下面说一下具体的一些计算:在MD5中有四个32位的被称作链接变量的整数参数,是如下设置(这个ABCD是初始的固定的值):

A=0x67452301,

B=0xefcdab89,

C=0x98badcfe,

D=0x10325476。

之后有四个非线性函数,将字符串和那四个链接变量经过一系列的复杂运算,算出一组新的A,B,C,D的值,如果消息小于512,也就是只需要计算一次,这时候将新的ABCD的值按ABCD的顺序级联,然后输出,就是MD5的值,如果消息大于512的话,就用第一次算的MD5的值进行后半部分的运算,以此类推。

举个例子

比如计算字符串“test”

十六进制0x74657374

二进制0b1110100011001010111001101110100

这里与448模512不同余,补位后的数据如下

十六进制

0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

二进制

  1. 0b1110100011001010111001101110100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000

将补位后的数据进行一次复杂的运算,计算出

A=0xcd6b8f09

B=0x73d32146

C=0x834edeca

D=0xf6b42726

数据小于512位,所以将ABCD通过小端规则转换就是MD5值:098f6bcd4621d373cade4e832627b4f6

如果我输入的数据不是test而是一串很长的字符,换算出来大于512小于1024,就需要计算两次,第一次先计算前512位的ABCD的值,算出来后再用这个ABCD去计算后面512位的的ABCD的值,最后算出来的ABCD经过拼接就是这串字符的MD5了

问题来了

如果这么一个情况,由两个字符串组成一个字符串($str=$a+$b),第一个字符串($a)我不知道也不可控,只可控第二个字符串($b),同时知道第一个字符串($a)的MD5值和长度,这时候我将第二个字符串精心构造一下,便可以算出合成的字符串$str的MD5的值

首先正向计算一遍

假如第一个字符串$a=“test”,为了方便转为十六进制0x74657374

我构造第二个字符串首先手动将$str补成一个标准的可以直接计算的512位

$str=0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

这样子,这时候再在后面追加一个0x746573748

$str=0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000746573748

这时候再将$str大于512位,程序会先将这串数据补为1024位,补充完如下

$str=0x7465737480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000074657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

这时将$str分为两部分

74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000

74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

这时候程序计算前一部分的ABCD的值,由于和之前算的test的数值是相同的所以

A=0xcd6b8f09

B=0x73d32146

C=0x834edeca

D=0xf6b42726

到了第二部分,第二部分的计算是用的第一部分的ABCD去计算,计算新的ABCD如下

A=0x226359e5

b=0x99df12eb

C=0x6853f59e

D=0xf5406385

最后算出来的MD5是e5596322eb12df999ef55368856340f5

这时候我们按照给定条件来计算一遍

我们知道的条件

1.$a的MD5(098f6bcd4621d373cade4e832627b4f6)

2.$a的长度=4

3.$b我们可以任意控制

由1我们可以逆推算出其ABCD的值

A=0xcd6b8f09

B=0x73d32146

C=0x834edeca

D=0xf6b42726

我们构造$b='\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00'+'test'

此时$str如下,由于不知道$a,我们假设$a="aaaa"

$str='aaaa'+'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00'+'test'

好了我们脑补一下程序计算str的过程

1.由于大于512位,先补全为1024位,

2.将其分为两部分

3.计算第一部分的ABCD的值

4.再用第一部分算出来的ABCD拿来算第二部分的值。

这里由于第一部分的ABCD我们可以逆推出来,我们可以直接跳过前三部分直接进行第四部分的计算,只需要将标准的MD5的源码里面的初始的ABCD的值改为逆推出来的那个值

我们用假的初始的ABCD计算一下

0x74657374800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002002000000000000

的MD5,发现是e5596322eb12df999ef55368856340f5,和上面正向计算出来的一样!

下面贴出来我用的算MD5的代码,以及测试文件

my_md5.py

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Author:DshtAnger
  4. # theory reference:
  5. # blog:
  6. # http://blog.csdn.net/adidala/article/details/28677393
  7. # http://blog.csdn.net/forgotaboutgirl/article/details/7258109
  8. # http://blog.sina.com.cn/s/blog_6fe0eb1901014cpl.html
  9. # RFC1321:
  10. # https://www.rfc-editor.org/rfc/pdfrfc/rfc1321.txt.pdf
  11. ##############################################################################
  12. import sys
  13. def genMsgLengthDescriptor(msg_bitsLenth):
  14. '''
  15. ---args:
  16. msg_bitsLenth : the bits length of raw message
  17. --return:
  18. 16 hex-encoded string , i.e.64bits,8bytes which used to describe the bits length of raw message added after padding
  19. '''
  20. return __import__("struct").pack(">Q",msg_bitsLenth).encode("hex")
  21. def reverse_hex_8bytes(hex_str):
  22. '''
  23. --args:
  24. hex_str: a hex-encoded string with length 16 , i.e.8bytes
  25. --return:
  26. transform raw message descriptor to little-endian
  27. '''
  28. hex_str = "%016x"%int(hex_str,16)
  29. assert len(hex_str)==16
  30. return __import__("struct").pack("<Q",int(hex_str,16)).encode("hex")
  31. def reverse_hex_4bytes(hex_str):
  32. '''
  33. --args:
  34. hex_str: a hex-encoded string with length 8 , i.e.4bytes
  35. --return:
  36. transform 4 bytes message block to little-endian
  37. '''
  38. hex_str = "%08x"%int(hex_str,16)
  39. assert len(hex_str)==8
  40. return __import__("struct").pack("<L",int(hex_str,16)).encode("hex")
  41. def deal_rawInputMsg(input_msg):
  42. '''
  43. --args:
  44. input_msg : inputed a ascii-encoded string
  45. --return:
  46. a hex-encoded string which can be inputed to mathematical transformation function.
  47. '''
  48. ascii_list = [x.encode("hex") for x in input_msg]
  49. length_msg_bytes = len(ascii_list)
  50. length_msg_bits = len(ascii_list)*8
  51. #padding
  52. ascii_list.append('80')
  53. while (len(ascii_list)*8+64)%512 != 0:
  54. ascii_list.append('00')
  55. #add Descriptor
  56. ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits)))
  57. return "".join(ascii_list)
  58. def getM16(hex_str,operatingBlockNum):
  59. '''
  60. --args:
  61. hex_str : a hex-encoded string with length in integral multiple of 512bits
  62. operatingBlockNum : message block number which is being operated , greater than 1
  63. --return:
  64. M : result of splited 64bytes into 4*16 message blocks with little-endian
  65. '''
  66. M = [int(reverse_hex_4bytes(hex_str[i:(i+8)]),16) for i in xrange(128*(operatingBlockNum-1),128*operatingBlockNum,8)]
  67. return M
  68. #定义函数,用来产生常数T[i],常数有可能超过32位,同样需要&0xffffffff操作。注意返回的是十进制的数
  69. def T(i):
  70. result = (int(4294967296*abs(__import__("math").sin(i))))&0xffffffff
  71. return result
  72. #定义每轮中用到的函数
  73. #RL为循环左移,注意左移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位
  74. F = lambda x,y,z:((x&y)|((~x)&z))
  75. G = lambda x,y,z:((x&z)|(y&(~z)))
  76. H = lambda x,y,z:(x^y^z)
  77. I = lambda x,y,z:(y^(x|(~z)))
  78. RL = L = lambda x,n:(((x<<n)|(x>>(32-n)))&(0xffffffff))
  79. def FF(a, b, c, d, x, s, ac):
  80. a = (a+F ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;
  81. a = RL ((a), (s))&0xffffffff;
  82. a = (a+b)&0xffffffff
  83. return a
  84. def GG(a, b, c, d, x, s, ac):
  85. a = (a+G ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;
  86. a = RL ((a), (s))&0xffffffff;
  87. a = (a+b)&0xffffffff
  88. return a
  89. def HH(a, b, c, d, x, s, ac):
  90. a = (a+H ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;
  91. a = RL ((a), (s))&0xffffffff;
  92. a = (a+b)&0xffffffff
  93. return a
  94. def II(a, b, c, d, x, s, ac):
  95. a = (a+I ((b), (c), (d)) + (x) + (ac)&0xffffffff)&0xffffffff;
  96. a = RL ((a), (s))&0xffffffff;
  97. a = (a+b)&0xffffffff
  98. return a
  99. def show_md5(A,B,C,D):
  100. return "".join( [ "".join(__import__("re").findall(r"..","%08x"%i)[::-1]) for i in (A,B,C,D) ] )
  101. def run_md5(A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,readyMsg=""):
  102. a = A
  103. b = B
  104. c = C
  105. d = D
  106. for i in xrange(0,len(readyMsg)/128):
  107. M = getM16(readyMsg,i+1)
  108. for i in xrange(16):
  109. exec "M"+str(i)+"=M["+str(i)+"]"
  110. #First round
  111. a=FF(a,b,c,d,M0,7,0xd76aa478L)
  112. d=FF(d,a,b,c,M1,12,0xe8c7b756L)
  113. c=FF(c,d,a,b,M2,17,0x242070dbL)
  114. b=FF(b,c,d,a,M3,22,0xc1bdceeeL)
  115. a=FF(a,b,c,d,M4,7,0xf57c0fafL)
  116. d=FF(d,a,b,c,M5,12,0x4787c62aL)
  117. c=FF(c,d,a,b,M6,17,0xa8304613L)
  118. b=FF(b,c,d,a,M7,22,0xfd469501L)
  119. a=FF(a,b,c,d,M8,7,0x698098d8L)
  120. d=FF(d,a,b,c,M9,12,0x8b44f7afL)
  121. c=FF(c,d,a,b,M10,17,0xffff5bb1L)
  122. b=FF(b,c,d,a,M11,22,0x895cd7beL)
  123. a=FF(a,b,c,d,M12,7,0x6b901122L)
  124. d=FF(d,a,b,c,M13,12,0xfd987193L)
  125. c=FF(c,d,a,b,M14,17,0xa679438eL)
  126. b=FF(b,c,d,a,M15,22,0x49b40821L)
  127. #Second round
  128. a=GG(a,b,c,d,M1,5,0xf61e2562L)
  129. d=GG(d,a,b,c,M6,9,0xc040b340L)
  130. c=GG(c,d,a,b,M11,14,0x265e5a51L)
  131. b=GG(b,c,d,a,M0,20,0xe9b6c7aaL)
  132. a=GG(a,b,c,d,M5,5,0xd62f105dL)
  133. d=GG(d,a,b,c,M10,9,0x02441453L)
  134. c=GG(c,d,a,b,M15,14,0xd8a1e681L)
  135. b=GG(b,c,d,a,M4,20,0xe7d3fbc8L)
  136. a=GG(a,b,c,d,M9,5,0x21e1cde6L)
  137. d=GG(d,a,b,c,M14,9,0xc33707d6L)
  138. c=GG(c,d,a,b,M3,14,0xf4d50d87L)
  139. b=GG(b,c,d,a,M8,20,0x455a14edL)
  140. a=GG(a,b,c,d,M13,5,0xa9e3e905L)
  141. d=GG(d,a,b,c,M2,9,0xfcefa3f8L)
  142. c=GG(c,d,a,b,M7,14,0x676f02d9L)
  143. b=GG(b,c,d,a,M12,20,0x8d2a4c8aL)
  144. #Third round
  145. a=HH(a,b,c,d,M5,4,0xfffa3942L)
  146. d=HH(d,a,b,c,M8,11,0x8771f681L)
  147. c=HH(c,d,a,b,M11,16,0x6d9d6122L)
  148. b=HH(b,c,d,a,M14,23,0xfde5380c)
  149. a=HH(a,b,c,d,M1,4,0xa4beea44L)
  150. d=HH(d,a,b,c,M4,11,0x4bdecfa9L)
  151. c=HH(c,d,a,b,M7,16,0xf6bb4b60L)
  152. b=HH(b,c,d,a,M10,23,0xbebfbc70L)
  153. a=HH(a,b,c,d,M13,4,0x289b7ec6L)
  154. d=HH(d,a,b,c,M0,11,0xeaa127faL)
  155. c=HH(c,d,a,b,M3,16,0xd4ef3085L)
  156. b=HH(b,c,d,a,M6,23,0x04881d05L)
  157. a=HH(a,b,c,d,M9,4,0xd9d4d039L)
  158. d=HH(d,a,b,c,M12,11,0xe6db99e5L)
  159. c=HH(c,d,a,b,M15,16,0x1fa27cf8L)
  160. b=HH(b,c,d,a,M2,23,0xc4ac5665L)
  161. #Fourth round
  162. a=II(a,b,c,d,M0,6,0xf4292244L)
  163. d=II(d,a,b,c,M7,10,0x432aff97L)
  164. c=II(c,d,a,b,M14,15,0xab9423a7L)
  165. b=II(b,c,d,a,M5,21,0xfc93a039L)
  166. a=II(a,b,c,d,M12,6,0x655b59c3L)
  167. d=II(d,a,b,c,M3,10,0x8f0ccc92L)
  168. c=II(c,d,a,b,M10,15,0xffeff47dL)
  169. b=II(b,c,d,a,M1,21,0x85845dd1L)
  170. a=II(a,b,c,d,M8,6,0x6fa87e4fL)
  171. d=II(d,a,b,c,M15,10,0xfe2ce6e0L)
  172. c=II(c,d,a,b,M6,15,0xa3014314L)
  173. b=II(b,c,d,a,M13,21,0x4e0811a1L)
  174. a=II(a,b,c,d,M4,6,0xf7537e82L)
  175. d=II(d,a,b,c,M11,10,0xbd3af235L)
  176. c=II(c,d,a,b,M2,15,0x2ad7d2bbL)
  177. b=II(b,c,d,a,M9,21,0xeb86d391L)
  178. A += a
  179. B += b
  180. C += c
  181. D += d
  182. A = A&0xffffffff
  183. B = B&0xffffffff
  184. C = C&0xffffffff
  185. D = D&0xffffffff
  186. a = A
  187. b = B
  188. c = C
  189. d = D
  190. print "%x,%x,%x,%x"%(a,b,c,d)
  191. return show_md5(a,b,c,d)

test.py

  1. # -*- coding: utf-8 -*-
  2. import my_md5
  3. import sys
  4. import six
  5. MD5_Hash=sys.argv[1]
  6. length=int(sys.argv[2])
  7. text=sys.argv[3]
  8. s1=eval('0x'+MD5_Hash[:8].decode('hex')[::-1].encode('hex'))
  9. s2=eval('0x'+MD5_Hash[8:16].decode('hex')[::-1].encode('hex'))
  10. s3=eval('0x'+MD5_Hash[16:24].decode('hex')[::-1].encode('hex'))
  11. s4=eval('0x'+MD5_Hash[24:32].decode('hex')[::-1].encode('hex'))
  12. secret = "a"*length
  13. test=secret+'\x80'+'\x00'*((512-length*8-8-8*8)/8)+six.int2byte(length*8)+'\x00\x00\x00\x00\x00\x00\x00'+text
  14. s = my_md5.deal_rawInputMsg(test)
  15. r = my_md5.deal_rawInputMsg(secret)
  16. inp = s[len(r):]
  17. print '填充完的数据为:'+test+'\n'
  18. print '----------------------------------------------------------'
  19. print '扩充完的数据为(16进制):'+s
  20. print '----------------------------------------------------------'
  21. print '截取最后分组的数据(16进制):'+inp
  22. print '----------------------------------------------------------'
  23. print '最终填充结果为:'+bytes(test).encode('hex')
  24. print "填充后的md5为:"+my_md5.run_md5(s1,s2,s3,s4,inp)

脚本使用时第一个命令行参数是一个服务端加密一个固定长度数据的md5,第二个参数是固定的长度

例如已知服务端加密一个15字符的md5:test.py 571580b26c65f306376d4f64e53cb5c7 15

MD5的Hash长度扩展攻击的更多相关文章

  1. hash长度扩展攻击

    这里面就放一张百度百科的解释吧,emmm 反正我是看不懂还是做一下题来巩固一下吧 CTF中的hash长度攻击 进入网页你会发现页面显示  我这里没有看到什么可以利用的,抓了一下包也没有什么有可以利 ...

  2. 实验吧——让我进去(hash长度扩展攻击)

    题目地址:http://ctf5.shiyanbar.com/web/kzhan.php 在页面源码没发现什么,于是用burp进行抓包重放 看到有setcookie,于是重新刷新页面拦截数据包(这次才 ...

  3. 实验吧Web-中-让我进去(Hash长度扩展攻击、加盐密码及Linux下hashpump的安装使用)

    打开网页,测试开始,注入费老大劲,看了大佬的blog才知道怎么干. bp抓包,观察发现cookie中有个source=0,在repeater中修改为source=1,然go一下,出来了一段源代码. $ ...

  4. MD5加密及Hash长度拓展攻击【通俗易懂】

    先放一个简单点的利用了Hash长度拓展攻击的题目 if($COOKIE["getmein"] === md5($secret . urldecode($username . $pa ...

  5. 浅谈HASH长度拓展攻击

    前言 最近在做CTF题的时候遇到这个考点,想起来自己之前在做实验吧的入门CTF题的时候遇到过这个点,当时觉得难如看天书一般,现在回头望去,仔细琢磨一番感觉也不是那么难,这里就写篇文章记录一下自己的学习 ...

  6. 哈希长度扩展攻击(Hash Length Extension Attack)利用工具hexpand安装使用方法

    去年我写了一篇哈希长度扩展攻击的简介以及HashPump安装使用方法,本来已经足够了,但HashPump还不是很完善的哈希长度扩展攻击,HashPump在使用的时候必须提供original_data, ...

  7. 哈希长度扩展攻击的简介以及HashPump安装使用方法

    哈希长度扩展攻击(hash length extension attacks)是指针对某些允许包含额外信息的加密散列函数的攻击手段.该攻击适用于在消息与密钥的长度已知的情形下,所有采取了 H(密钥 ∥ ...

  8. [De1CTF 2019]SSRF Me-MD5长度扩展攻击&CVE-2019-9948

    0x00 打开题目查看源代码,开始审计 这里贴上网上师傅的博客笔记: https://xz.aliyun.com/t/6050 #! /usr/bin/env python #encoding=utf ...

  9. 实验吧_天下武功唯快不破&让我进去(哈希长度拓展攻击)

    天下武功唯快不破 第一反应就去抓包,看到返回包的header中有FLAG的值,base64解码后得到下图所示 这就要求我们在请求头中post相应key的值,我直接在burp中尝试了多次都没有用,想起来 ...

随机推荐

  1. TFS体系结构和概念

    TFS体系结构和概念 TFS是Team Fundation Server的简称,是微软VSTS的一部分,它是Microsoft应用程序生命周期管理(ALM)工具的核心协作平台,简单的说它是管理和开发软 ...

  2. Python学习入门基础教程(learning Python)--5.7 Python文件数据记录存储与处理

    本节主要讨论Python下如何通过文件操作实现对数据记录集的存储与处理的操作方法. 在Python里和其他高级语言一样可以通过文件读写将一些记录集写入文件或者通过文件读操作从文件里读取一条或多条和数据 ...

  3. .NET基础——基本概念

    1.   .NET.C#(sharp)和JAVA .net是一种多语言的平台,开发.net可以用多达几十种语言进行开发. C#(sharp)是一种编程语言,可开发基于.net平台的应用. Java既是 ...

  4. C语言之函数的介绍

    函数的介绍 遇到的问题: 1.代码看起来特别多,不简洁 2.修改起来非常麻烦,需要所有用到的地方都修改 函数就可以解决上述这两个问题 函数可以理解为一个打包带,就是把一段代码打包起来,用到的时候只要写 ...

  5. kibana使用的lucene查询语法

    kibana在ELK阵营中用来查询展示数据elasticsearch构建在Lucene之上,过滤器语法和Lucene相同 kibana4官方演示页面 全文搜索 在搜索栏输入login,会返回所有字段值 ...

  6. D3.js:饼状图的制作

    假设有如下数据需要可视化: var dataset = [ 30 , 10 , 43 , 55 , 13 ]; 这样的值是不能直接绘图的.例如绘制饼状图的一个部分,需要知道一段弧的起始角度和终止角度, ...

  7. Android学习笔记(三)Android开发环境的搭建

    一.配置JAVA环境 二.配置Android开发环境 可以安装adt-bundle-windows,该压缩包一般自带Eclipse.或者安装Android Studio,要注意SDK的版本是否符合要求 ...

  8. jQuery 之玩转 checkbox

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  9. 一台服务器上同时启动多个 Tomcat

    在同一台服务器上启动多个 Tomcat 服务,需要修改 conf/server.xml文件里的三个部分,如下: 1.修改Http访问端口(默认为8080端口) <Connector port=& ...

  10. linux 查看磁盘占用情况

    查看"/usr/local/"路径下,所有文件大小总和.只列出总和,不显示该路径下各子文件的大小. du -sh /usr/local/ 结果显示如下图: 如果要详细显示出各子文件 ...