青春时代是一个短暂的美梦,当你醒来时,它早已消失得无影无踪了。
 
今日:0    总帖:23
admin
780
Win7及以上的系统已经不再支持Debug,想体验需要自行搭建模拟环境 在cmd中(Win98为command),输入debug回车,进入debug命令,然后将以下内容复制进去,即可看到e100 33 f6 bf 0 20 b5 10 f3 a5 8c c8 5 0 2 50 68 13 1 cb e 1f be a1 1 bf 0 1 e11b 6 57 b8 11 1 bb 21 13 89 7 4b 4b 48 79 f9 ad 86 e0 8b c8 bd ff ff e8 20 e134 0 3d 0 1 74 1a 7f 3 aa eb f3 2d ff 0 50 e8 f 0 5a f7 d8 8b d8 26 8a 1 aa e14f 4a 75 f9 eb de cb 57 bb 21 13 8b c1 40 f7 27 f7 f5 8b fb ba 11 1 4f 4f 4a e168 39 5 7f f9 52 8b c5 f7 25 f7 37 2b c8 95 f7 65 2 f7 37 95 2b e8 fe e fe e181 10 79 6 c6 6 fe 10 7 46 d0 14 d1 d1 d1 e5 79 ec 5a b8 11 1 ff 7 4b 4b 48 e19b 3b d0 75 f7 5f c3 83 f7 83 a6 5d 59 82 cd b2 8 42 46 9 57 a9 c5 ca aa 1b e1b4 4f 52 b4 92 3f ab 6e 9e a8 1d c6 3 fc e 6a e7 ae bb 5f 7b 10 b8 b4 f7 8 e1cd e2 bf 36 4e 39 9d 79 29 3f a f9 36 52 16 fb 5 e8 e5 a6 c2 e9 b0 43 d3 a3 e1e6 cf d3 fd fd cb d1 4c 5e e0 63 58 86 bb 3e 9 c1 20 bc cc 91 a3 47 81 70 b3 e1ff d6 1a 9e c2 c9 12 e7 4e ad f4 5f e3 30 e9 9 39 d7 e8 f9 f4 d2 44 e8 d7 22 e218 be e2 ce 88 25 cf 30 4a a8 29 ae 3f 47 c6 2d 85 e9 73 54 13 b e6 e0 34 65 e231 e2 50 8a 89 18 5f ce 70 99 3 5f 42 bf eb 7 ae d0 ca 5 22 8d 22 a5 b7 f0 e24a 90 81 bc 7a bc dc 5 db c0 6a 2 e5 57 38 be 60 cb ac ba a5 3b 9d f1 77 38 e263 a6 84 d1 3c af 49 d8 6a 45 a2 76 60 21 12 c0 c2 44 f2 5e bb e5 37 a9 2b e27b ec 4a 8c 4c f2 f7 a9 58 71 2b ba 6d d6 6a e5 60 46 e0 da e5 b9 90 e5 a3 e293 f7 7f 31 60 58 f0 c4 88 10 4e 3c a3 ee 4e 11 55 8f a 92 eb db ad 7a 9c f e2ac db 5a 28 96 da 87 ae 91 91 2d e3 5e ea df 6 95 71 67 71 40 ce d1 2e 31 6d e2c5 c1 9c d8 6a 76 9b 4a e8 36 44 d6 76 d 30 5 ff d4 1b ac 1f 32 65 31 bf 55 e2de 26 b a4 55 e1 5d 5e 16 ed 97 48 6c 77 fb 81 86 e f9 18 bd d4 f4 8b de 1d e2f7 ba d 47 75 3 89 4b 3e dc 27 86 1c d0 17 89 48 d1 a6 8d d4 2b 54 4e 8f b0 e310 2 e1 6b 1a 75 78 ea 21 91 13 c0 cf 78 a0 ab f3 35 c6 b4 c8 90 8d d7 45 e7 e329 c 5b a4 ba 52 10 64 f5 4a 50 b7 ec 46 22 15 23 84 30 81 5c df 61 5a 8f 67 e342 c4 63 57 6d f7 26 92 a3 1f e5 3 a5 0 54 41 8 48 7c 26 90 33 82 9c 91 b0 e35b ab 78 5d df 99 e0 b9 fc 5 36 ac d9 49 91 ab 20 a2 63 48 89 ce 5c 60 64 f0 e374 63 d9 a8 38 3b d3 e6 4c 8c 23 34 4e 20 51 93 5e 6d b4 7a 22 9b 4c f2 d3 e38c c4 f8 3 6f 47 40 f4 f8 45 9b 83 f3 83 6 31 d0 0 17 82 83 dc 67 f9 62 77 e3a5 90 3b d9 ec f3 55 96 b8 d9 db 79 55 f1 e5 8c 5e f2 e5 2e b0 b 6e e2 81 25 e3be 93 8e b5 dd 5b 46 f9 af ed 6 12 cf c9 1d f0 f7 3b 16 2d c6 58 73 8d e9 5f e3d7 fd 5a b6 a1 94 4d 1a 8 ff eb b7 6 80 c7 86 83 b6 b9 fd 1c e0 c c3 2e a0 e3f0 2f b 3e 3 6b 29 e1 27 85 1c ea 6d df b3 a3 ed 65 4a 9a 59 3b 54 e 4b ae e409 9e 27 f0 4d 3b c 4c 46 b7 e5 57 1b 1f 1f bb 80 86 f5 b7 ef 73 52 bf 2c c7 e422 ed a b7 81 2 f3 90 3e ee cc 6c eb f 38 1 6c 68 b1 d 45 78 b2 f f6 83 b0 e43c c4 33 df b1 d1 91 98 1e 81 a5 e2 59 9f f4 8c b6 72 8 a7 8c f6 e a3 b2 1f e455 d9 d3 23 f0 7c 5e 5f 68 61 8b 45 da 1d 91 ec 8d 4e ea 1a 38 85 94 aa ac e46d f2 4 f6 c4 e5 92 8e 9a 4e 83 e1 73 e8 cf 2a 5c 2b 7e f1 30 2 8a e6 28 1a e486 3b ce bc 96 aa 7f eb 87 cd 8b 96 2d 9 59 7a a0 1a 43 62 9a 9e 4f ff 8e d9 e49f ce d6 a4 70 79 cd 65 fa 2e 92 14 29 f7 6c 74 4b 49 60 80 bb ff 41 bb 2d e4b7 60 33 3f 98 77 9a 1 ee a6 a3 da bc ba e9 f3 72 f4 7c c3 59 2 a6 44 a4 c8 e4d0 c8 54 93 ce bd 69 bb b9 43 21 2c c4 ea 4a 5c 3f 75 60 f2 b4 91 ca 9 82 e3 e4e9 a e9 a6 20 b9 76 50 ed 47 e9 fe 6d 41 34 13 2f 28 2f 4e f4 da e 3c 78 6c e502 b1 79 87 45 98 a4 d4 c3 b3 29 c2 4a 8b ed a6 54 e2 1b 31 62 60 ff 2c 1d e51a 21 0 15 b2 4e 5c c 2 d 83 fa a2 f3 8a 5 12 72 4a c7 44 7c 91 d4 be b a f2 e535 70 52 fb b4 a2 df 89 de ff c4 96 73 c9 c ed d3 c9 8e 5c dc 8e d1 3b de 8c e54e 53 a2 8b f9 e9 91 dd d6 df 6e 74 d1 dd 34 60 8f 9e 32 7f 3b ec 79 a3 83 e566 45 78 b4 2f 1c 50 7b 7a 97 b0 9d 2d c dd 8a 26 cd 7d 8c 4c 5a 8a 4c f9 a4 e57f 11 f9 2c 6c 92 e9 b5 cb 56 89 8c be f6 64 fa 25 43 fa 6f e2 c8 3a 18 a8 e597 f0 e9 f4 c2 86 e6 2b 44 67 4a b9 34 9 ed 5f 33 42 62 d4 8a 1e 5b 31 67 cd e5b0 3d 71 6d 83 fd 36 20 69 ea 1 c3 e6 e6 de 99 aa 7 11 5b 59 8a 1f 43 83 52 e5c9 ea 5d 8c 6a 69 c7 3 eb 4e 3b 88 a5 5f b1 6e 27 5f 3 5c 28 c 9b 6c c3 f8 e5e2 e5 b9 d6 11 d6 8b fa 5c 8 c7 1 eb 45 db f3 6c 9f 16 46 61 51 ed df f bb e5fb c0 c4 1e 64 68 98 4 79 30 94 72 df d4 cd 1f 7f 72 c6 82 2e 79 47 4e 8c 4b e614 a2 c7 e2 36 df 76 fd a4 b6 4e db 96 40 3b 8b b5 d4 85 64 c6 0 2c ad 9d 27 e62d 14 99 82 4b bc 9 fa 94 b5 db 7c 98 eb b 13 a7 b0 79 1d 7e c5 45 aa 20 49 e646 be ff 9d 64 0 5d c ec 6 5 ad f2 38 6b ed 7a d6 b2 c7 2e 6a a6 12 4b ff 55 e660 20 3b a 77 f b9 0 9d 57 4a ad ce a4 d3 ff 1 4f fb 53 54 88 f 1 ed 4b 56 e67a 15 c8 dc 28 bf f2 72 d4 10 1f 99 42 69 9e 78 e2 47 82 93 31 d0 2d be 9f e692 93 93 9a 1b 80 c0 10 c 53 78 a0 26 2a 96 4f 74 4b 16 c7 9c 8d ad ac fb 16 e6ab 15 c6 fd c9 a4 14 48 62 47 20 c9 41 ed 61 f8 9b f8 ff ba 39 50 65 87 ee e6c3 bd ce 95 c0 fb a5 7e d8 cd 27 fd 2c 74 3 c1 1b 89 b9 51 d5 e3 da ef 9e 6 e6dc f0 aa a9 a7 fb 87 4c 5d cd ff 65 36 8c 73 6f 9 c6 78 9a b6 77 db df 81 68 e6f5 3b b8 ae 5d e1 af d4 e6 66 8c d6 a4 83 9f 37 3c 1 dc a2 a6 57 c2 20 1b 90 e70e 75 df cd a5 62 a5 36 79 fb 35 8a 9b b0 a0 a5 c3 37 6f 80 72 bc 52 30 8d e726 9f 7a 64 d3 7 41 45 d8 68 97 f2 aa 1c a1 6c 7c 9d 32 7d ad 15 b1 53 e3 33 e73f 8a ed e9 49 d4 cf dc 96 22 37 36 11 9d 7f f0 4d e0 62 31 b1 c7 69 c4 79 e757 ac 20 1 e8 3c 6a 8c 32 cb 52 63 36 68 f4 10 2b 9c 21 4f df 5d 60 92 39 91 e770 e2 f9 c9 7d ca 48 3 3f 21 dd 6c f 23 2e 61 3a 9f ba c3 f9 4e 7 ea ed ef e789 71 4a 72 3a ed 23 3d 77 b5 ed d5 1d f6 a4 99 fa ef 98 dd 2 98 80 b6 7c a3 e7a2 62 96 7b 8e bf 7b 81 9f 9a ce 3f 12 40 2e 25 db 84 16 dd 2e 86 f f4 b2 7e e7bb 5e b4 14 6a f3 29 b1 a4 57 d5 a8 17 6f 87 a4 74 5b 9b 17 79 f1 ec 33 c8 e7d3 f0 1d b2 7e a8 4d 95 7f 5f 9 d5 1a 5a 45 f4 41 c6 d 3f eb 66 2a c0 e8 5b e7ec 3c bd 50 ad f1 53 9d 2e 45 9a d8 7d 2c 17 a8 6e 15 48 13 39 53 ed 3d 78 e804 ad f 3a 65 a3 3e 2e fa ca 7 94 4a 1f b4 d8 7e 47 8a 8e de e7 7e 34 c1 69 e81d 7f 6a aa 66 58 18 31 24 72 13 22 34 8a 56 36 87 df c2 d 8e 3f 71 a2 5f 25 e836 8b 8d 4 78 fd c9 45 d1 55 79 c1 9f 13 84 1b c8 5 db 95 d0 7c 64 96 20 51 e84f c4 e0 5e ee 47 8a 11 ac fb 9 e0 bb 40 db 86 84 12 93 b9 c9 f2 9c 63 47 c9 e868 eb ad 1 3e fa 6d 3f a 64 5b 58 56 27 f ca 5d e0 30 bc 3e 10 5d ec 17 28 e881 85 5 51 8e 95 a3 94 3a a8 f1 96 f2 f 29 5c 97 dc 47 db 9d 6c 63 e8 e7 f0 e89a e4 a 70 f8 f1 47 54 d3 2d 32 7c ef bb 9a b4 1b 0 2b d6 dd e7 30 b a2 75 e8b3 c7 f5 d0 31 d7 d2 8a b0 ac 1c 6d 60 3a f7 c2 db 1e 6d 7 f6 8f 35 88 e5 7f e8cc 3c 26 81 34 a0 32 a3 25 18 6e 73 b2 a0 f1 cb 86 61 e7 65 8b 76 98 19 6f e8e4 c0 62 9b a3 cc 18 5e 40 12 97 2b d0 15 79 de 19 ea df 7a 59 2f b5 d7 39 e8fc 52 e2 6 f1 3 a0 a5 d9 1b 88 93 4d 30 c8 2d f5 db 55 ea 85 6f a 3f dc bd e915 57 15 6a a3 a3 3e 8e ad 2d da a0 ca 75 7c 57 8b c5 cb b 1d 2c 8e c6 96 2e e92e 6d 59 83 7d 64 72 ca 80 2e 6 a4 ff f6 f2 d5 1e 7 4 ba 34 6e 9 86 25 aa 4e e948 e0 7f f5 32 47 3e 7c 43 d8 28 c4 1c 11 1d bd 33 3 b5 ca 13 43 34 2 b1 a0 e961 57 ed 9d 3c 23 d4 45 b2 6e 81 6e af 3e 67 90 be 59 a5 45 34 53 46 85 d1 e979 25 ee 7d cb a4 db 12 c3 aa 17 61 9a fb 66 40 76 fe 3a 69 96 c0 91 14 a7 e991 5d cc 9f f6 73 59 ee b8 55 97 20 26 ff 99 ec 72 41 b5 27 21 6e ae 8a d0 e9a9 e4 d3 da 6f c4 53 c5 f8 b3 a7 a1 5d 66 93 d8 b1 89 40 23 92 c0 90 fb cb e9c1 e7 6b 4e 51 0 5d 57 f7 cd 1 e2 88 bf 44 9f ef c4 33 ce fa 46 46 a1 86 b e9da 7a 84 66 66 b9 2 ec 10 c6 a1 d4 c1 18 33 b1 d1 2 18 ad 2f 53 e4 b9 33 59 e9f3 be 3c af 80 4c 8a d5 76 c 3b a7 e2 97 94 15 75 4d 17 d5 97 cf f9 4a d0 6e ea0c bb 27 20 fc f1 f5 9 a8 df 4d b6 5d f0 1d 69 3b 76 35 82 a4 f3 56 64 39 5b ea25 6b b3 7 e7 5 8e 82 11 22 a8 1a db c8 3e 67 4a 3 7e 72 51 d6 3d 1a 1c f6 ea3e b8 da 4b 18 8a 15 9d d0 a4 84 96 3e cd 3 f9 3a 30 f3 fb 8f 6e 2 73 eb 52 ea57 93 95 cf dc 6f 48 fb ab d2 a9 70 b4 e2 23 8d 72 86 a8 fa 78 98 1d c5 fe ea6f 8a 51 88 2b b7 58 b0 ca ae 40 8a 33 32 75 1 6 c0 d4 b7 da 2a a7 bb ad f7 ea88 48 98 5a bc d3 d1 e6 16 97 c3 80 ab 73 ac 32 11 41 1f d 5d aa 0 dc d9 6e eaa1 fc 30 6 ef 11 60 27 a2 5f eb 5f b9 35 8 23 4 be 10 c0 85 3e 55 b3 82 fd eaba f7 c3 24 9f 2d 83 94 32 36 de ff 7c 87 7f 4a 80 7 2 23 cf a4 52 eb 3e 19 ead3 a0 b4 a 94 1a 40 58 d9 16 6d c0 64 c4 69 ed 60 46 65 cb df 58 38 0 51 c3 eaec ad a0 37 e4 cf ab f7 6c 24 7d 9 48 65 4a 9f 91 ad 1c 79 a4 a1 78 55 c e8 eb05 44 5b d ef 51 bd ea 2d a7 42 57 ab 3a 4f 2 b 3 19 6a 4d 72 76 5c 97 0 6c eb1f c5 5d bc dd e7 81 cf 8d 34 38 50 3c 98 58 cc 41 aa 99 90 af fe 4e 96 77 eb37 ed 54 18 ce 2c d1 5d 34 cb 79 50 ff 28 96 44 e0 51 64 6 a8 b7 6e 8c 62 c4 eb50 66 95 81 4f 8c f6 26 ba ea 5d d2 79 b1 e4 e9 29 fc a fd b3 85 8c e6 52 dd eb69 33 bd 5d c7 39 ef 6 ef 9e a6 6a 61 9c 9f d5 54 b4 fa a1 d4 10 9b ff 7e 33 eb82 11 52 99 c7 26 6e a1 36 8a ad ee 48 7a 2c 7f d5 b7 27 8a 6b 37 c 71 39 85 eb9b 9c ba a8 a 17 b9 d0 51 56 95 c2 3b 5 a7 31 c5 8b 5c 95 6e 4c 89 6f 17 ef ebb4 d4 5a a 77 65 e1 49 b2 e8 72 ac 3c f0 6b 71 fa 3 c7 ca fc ad f9 55 22 ec ebcd 58 2f 1c fa 29 cf 73 b4 ad 51 5c f8 66 70 59 5d 70 3e d1 3f c4 eb ec f1 ebe5 7 78 6a 93 67 9f 44 fc cb 5b 95 ff 74 c0 b7 42 77 26 c9 aa 8c ed 39 a2 db ebfe 9c b3 eb 3d 4a 1e 9b 89 e4 d8 a8 27 74 ef a3 ed a5 24 5d bb ab d0 fe a1 ec16 29 ab df 75 a a6 23 0 cc f1 14 72 9b 1a 55 7e e5 d1 da 98 dc c4 cf ab 34 ec2f ba 8d de 4a 59 6 13 dd d8 44 3c e bb 56 95 ae 97 e2 3b 49 e5 9a 6b a2 53 ec48 c1 33 35 24 1b 33 17 c3 8a 8c 12 3d 3d 4e 5b 75 22 30 67 4f a0 5d 3a 78 ec60 88 a 11 35 7 b1 77 42 32 a8 c3 bb 20 fb 98 5 d6 ac e7 3a 63 35 90 93 9e ec79 44 24 2e 1b d7 8c aa 29 53 4d d9 ab eb e6 1 56 c4 fd 54 a3 bd 14 5b b0 8f ec92 ce be 23 24 93 c4 48 18 a3 e7 4 5 4b 78 cc 79 dd 3 56 a4 ed dd 5f 98 41 ecab 1b 68 4c c1 bb 41 c2 1e 3e 94 8e ef 28 1e b 76 e 4f 36 b1 c 6e e2 18 17 ecc4 20 fc 35 40 1f e4 6d a4 18 bb bc d5 9e ea 85 86 af af 63 d4 13 66 92 c4 ecdc 2b 69 84 ca 23 2b d3 66 81 6b 81 73 26 4 85 36 21 4c 49 44 75 64 39 16 3c ecf5 ed e0 6d 44 75 45 30 43 68 c0 78 fc d0 17 b eb 81 3e c3 ba 1b f 4d ae c5 ed0e 55 1f c 39 12 5d 8 65 f1 34 59 de dd 98 56 17 43 38 66 49 9a eb db c1 87 ed27 51 38 cc b7 5f 98 fd 43 be 2d bb 74 f3 f8 f2 36 3d a4 34 a5 7e d2 26 cc ed3f 84 1f ea 56 f0 80 18 69 4d 88 41 fc 56 fd 41 3b 1e e 9 27 4f f6 3b 62 4e ed58 5a 1b 2a 4e 85 8c b2 4f 79 ef 59 4e e 73 3d bd c4 ca 60 e7 4a 47 90 b5 8 ed71 2a f0 4e dc ba 66 ae 48 2b 31 73 a2 11 c 32 ff 54 14 77 6b d6 58 4b bf ee ed8a f6 6a bc dd 1 88 d da a9 f 81 24 c5 f8 72 9a db d5 c8 2a 80 a9 16 d7 c6 eda3 b1 91 c0 a9 95 40 b5 b3 a8 2a 28 c6 92 16 ab 54 7d f8 93 5f 3a 17 c8 45 edbb a9 f0 e0 71 23 76 53 38 a5 a1 cc d4 f1 f2 3c 2b 46 43 a1 d5 ba e d7 19 7a edd4 c2 e1 8f 67 1d d 98 9d a1 79 9d 1b 20 7f 4d e7 bf f9 ff fe aa 28 ab 8f c eded 4d 50 33 e3 26 fc 3c 3 3a 2b 26 12 f7 1 8f ee 97 4c e6 6 2b d9 1f a1 4a ee06 77 44 d4 8b b7 3e 5e 2d 18 c3 54 68 99 a8 8d 92 96 9e 9d ab 33 38 ff b8 ee1e ee 78 c6 7b b5 84 95 d3 6 27 ae 5d 27 38 a 38 8e f0 1 a5 96 4b d7 9b 42 ee37 e5 6f 57 75 4c e9 78 2d 5b ec b6 d2 29 e2 a8 92 95 9c 65 2a 3e bf 8d e0 ee4f bf b3 ac c8 e 7e 13 af 88 26 7d 48 5a c7 39 29 36 d2 90 e8 3b 3 d0 61 1a ee68 d2 e8 a8 f ba 8e a1 9f df 12 ab 54 7 23 98 de 62 af 4c 7e d4 fb 6b 2 6e ee81 40 40 37 b7 73 f2 d8 81 be 29 d2 99 c0 73 25 1a 3c 92 75 6e bd d7 79 79 ee99 4 14 c0 4e 99 57 66 93 74 ec b0 29 7c df 61 b0 3 3a d1 c3 fa a4 f7 f 9f eeb2 d3 f 0 b9 2a 5a 3a c5 88 25 b8 b9 cc 82 3 57 3a e1 7b 51 75 70 a6 74 1a eecb ca cb 3 18 68 ca 77 fe 1b ad cd 68 7f 36 85 fc b7 4f a0 11 da 69 fa 79 87 eee4 d6 b9 21 dd 3e 70 db dc 84 d4 6e d1 20 4 af f6 32 a2 8e d 54 25 fe 7 54 eefd e 7a 74 4b a0 4b f7 f4 e8 74 22 e9 98 70 fb 25 2e f4 64 57 75 28 85 45 53 ef16 3a 2e e2 3c 54 36 e9 29 6 67 59 43 10 7e c1 49 cd 5e f9 97 a 58 5f 8a 11 ef2f 4f 3d 9a e2 2b 22 58 fa be fc 69 91 7a 8c 3f 77 9f c9 3b 54 26 23 93 b3 ef47 85 de ae f5 bd c5 47 4c c4 cd 5e ad bc 8f ba 31 f6 e4 70 fb 6e a7 96 d5 ef5f ad 10 80 39 43 97 4f 10 cc 1b 8f 8d cd 4c 63 4 d8 1e 85 70 41 6c a8 eb df ef78 7f 36 c5 60 a7 12 9 16 73 fe 75 3a 2d 40 29 7d aa a 5c 2 29 23 0 a6 e5 6b ef92 24 6d 9b 20 e5 7 cb 40 b0 38 59 9c a7 69 6a 70 d3 38 ef e2 b2 11 3e ea 2a efab f9 2b 2e 43 1d 65 cf d6 1b ef 83 5a 5f e6 c5 62 16 ca 5e 4c a6 39 e4 53 efc3 2d 23 d2 5e 7e 15 54 8a 8 b7 3d bb 88 59 b9 9e a2 7c 42 1f a2 77 3c 5b 9 efdc 6d fa 8f 21 46 1a 3e ed ce 49 56 1d 29 2d 70 3 a7 6f 75 ac 1 87 ff 27 86 eff5 73 49 28 85 2d 97 7a 84 e 37 3d 86 10 21 4c e2 74 62 6b 51 70 8f 15 72 f3 e100e 81 b2 a9 9d 8a 63 ad 1b d5 aa 8a dc 96 3c e7 47 16 51 fc 87 50 9 b7 60 e1026 29 33 52 fb b0 df 70 c5 65 4a 60 3b c d7 a8 29 47 51 f7 8a 77 f3 99 3f e103e 38 16 60 de 68 27 b2 24 7 62 a2 fd 40 86 b2 75 c3 3c 2f 3d fa 9 d9 a9 9a e1057 71 3c ce 46 94 0 f9 bc 46 7f b8 2e 85 7f 7d d3 8d ea b4 63 81 59 10 bb e106f 57 d0 b6 ab e1 83 74 1e 25 d5 73 78 18 b1 60 62 c f4 76 8d 17 d5 ed 23 e1087 23 e4 f6 32 64 5a 61 9 63 f6 92 57 d5 29 40 d6 3b ba 63 72 18 0 25 1b 7 e10a0 ee 7f 25 4a fa 6 74 19 46 e3 e8 89 7a c6 56 54 a7 43 13 4e bf 97 a5 6f e10b8 99 2f ac 33 4d fa 58 3a 5a a a4 1a 74 62 c8 4f 3b 78 9 d7 ee 7e ee 2d 69 e10d1 30 40 ea 47 82 3b 85 8e 3 23 8f 74 4e 8 35 ab 74 4 1 57 d5 85 b1 6b 1e e10ea f4 7d 1e d2 1e b3 fe f3 12 10 32 39 51 48 2d 6f e5 d3 a3 8c 8 8 g
2 0 230天前
admin
916
转自看雪论坛:https://bbs.pediy.com/thread-249594.htm通过CPUID原理:通过检查功能号1的CPUID返回的ecx的最高位是否为1,如果为1,则在虚拟环境下运行。真机的最高位不为1。检测处理器是否支持 cpuid 指令(忽略这一条)现在的CPU都支持 cpuid 指令,没必要去检测是否支持,除非在很早的的机器上运行才有必要(那好像也要80486的机器吧)。在 eflags.ID 标志位是 Processor Feature Identification 位,即最高位,通过修改这个标志位的值,以此来检测是否支持 cpuid 指令。要使用CPUID指令,输入eax表示功能号(类似中断的用法)输出eax,ebx,ecx,edx在EDX和ECX中返回的功能标志表明着该CPU都支持那些功能。ECX返回值定义如下(资料来自Intel):bit Name Description --------------------------------------------------------- 00 SSE3 Streaming SIMD Extensions 3 01 Reserved 02 DTES64 64-Bit Debug Store 03 MONITOR MONITOR/MWAIT 04 DS-CPL CPL Qualified Debug Store 05 VMX Virtual Machine Extensions 06 SMX Safer Mode Extensions 07 EST Enhanced Intel SpeedStep® Technology 08 TM2 Thermal Monitor 2 09 SSSE3 Supplemental Streaming SIMD Extensions 3 10 CNXT-ID L1 Context ID 12:11 Reserved 13 CX16 CMPXCHG16B 14 xTPR xTPR Update Control 15 PDCM Perfmon and Debug Capability 17:16 Reserved 18 DCA Direct Cache Access 19 SSE4.1 Streaming SIMD Extensions 4.1 20 SSE4.2 Streaming SIMD Extensions 4.2 21 x2APIC Extended xAPIC Support 22 MOVBE MOVBE Instruction 23 POPCNT POPCNT Instruction 25:24 Reserved 26 XSAVE XSAVE/XSTOR States 27 OSXSAVE 31:28 Reserved 下面是使用CPUID检测的核心汇编代码: .CODE getcpuid PROC xor eax,eax mov eax,1h cpuid mov a,eax mov b,ebx mov c_var,ecx mov d,edx ret getcpuid ENDP END 通过利用IoInitializeTimer配合IoStartTimer的定时器来循环判定。遍历模块我们说到的第一种CPUID的方法可能通过修改VMX的配置等方法绕过。还有一种方式是遍历当前系统中所有的sys。我们要查找的是vmmouse.sys,vmrawdsk.sys,vmusbmouse.sys中的任意一个。核心是利用NtQuerySystemInformation:#include <ntddk.h> #include <windef.h> typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY { HANDLE Section; PVOID MappedBase; PVOID Base; ULONG Size; ULONG Flags; USHORT LoadOrderIndex; USHORT InitOrderIndex; USHORT LoadCount; USHORT PathLength; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef NTSTATUS(*NTQUERYSYSTEMINFORMATION) ( IN ULONG SystemInformationClass, OUT PVOID SystemInformation, IN ULONG_PTR SystemInformationLength, OUT PULONG_PTR ReturnLength OPTIONAL ); VOID getcpuid(); BOOLEAN CheckDriverModule(); UNICODE_STRING symLinkName = { 0 }; PDEVICE_OBJECT pDevice; PETHREAD pThreadObject = NULL; BOOLEAN boom = FALSE; //eax为CPU型号 //若为虚拟机,则ecx最高位为1;如果是物理机,则最高位为0. //code in cpuid.asm DWORD a = 0, b = 0, c_var = 0, d = 0; VOID Unload() {//PDRIVER_OBJECT DriverObject if (pThreadObject) { boom = TRUE; KeWaitForSingleObject(pThreadObject, Executive, KernelMode, FALSE, NULL); } if (pDevice) { IoStopTimer(pDevice); IoDeleteSymbolicLink(&symLinkName); IoDeleteDevice(pDevice); pDevice = NULL; } DbgPrint("Unload --------"); } VOID TimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID context) { DbgPrint("In TimerRoutine\n"); //Begin normal check getcpuid(); c_var = c_var >> 31; if (c_var){ DbgPrint("Running in the virtual machine 2. Find VMWare by CPUID!!!!\n"); } } BOOLEAN CheckDriverModule() { BOOLEAN bRet = FALSE; NTQUERYSYSTEMINFORMATION m_NtQuerySystemInformation = NULL; UNICODE_STRING NtQuerySystemInformation_Name = { 0 }; PSYSTEM_MODULE_INFORMATION ModuleEntry = NULL; ULONG_PTR RetLength = 0, BaseAddr = 0, EndAddr = 0; ULONG ModuleNums = 0, Index = 0; NTSTATUS status = STATUS_SUCCESS; PVOID Buffer = NULL; RtlInitUnicodeString(&NtQuerySystemInformation_Name, L"NtQuerySystemInformation"); do { m_NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)MmGetSystemRoutineAddress(&NtQuerySystemInformation_Name); if (m_NtQuerySystemInformation == NULL) { bRet = TRUE; break; } status = m_NtQuerySystemInformation(0xb, NULL, 0, &RetLength); if (status < 0 && status != STATUS_INFO_LENGTH_MISMATCH) { bRet = TRUE; break; } Buffer = ExAllocatePoolWithTag(PagedPool, RetLength, "ytz"); if (Buffer == NULL) { bRet = TRUE; break; } RtlZeroMemory(Buffer, RetLength); status = m_NtQuerySystemInformation(0xb, Buffer, RetLength, &RetLength); if (status < 0) { bRet = TRUE; break; } ModuleNums = *(ULONG*)Buffer; ModuleEntry = (PSYSTEM_MODULE_INFORMATION)((ULONG_PTR)Buffer + 8); for (Index = 0; Index < ModuleNums; Index++) { if (strstr(ModuleEntry->ImageName, "vmmouse.sys") || strstr(ModuleEntry->ImageName, "vmrawdsk.sys") || strstr(ModuleEntry->ImageName, "vmusbmouse.sys")) { DbgPrint("The Module Name is %s\n", ModuleEntry->ImageName); bRet = TRUE; break; } ModuleEntry++; } break; //Amuse } while (TRUE); if (Buffer) { ExFreePool(Buffer); Buffer = NULL; } return bRet; } VOID CheckVmWare(PVOID context) { LARGE_INTEGER sleeptime = { 0 }; sleeptime.QuadPart = -20000000; while (1) { if (boom) break; if (CheckDriverModule()) { DbgPrint("Running in the virtual machine 1. Find VMWare!!!!\n"); } DbgPrint("Thread is working"); KeDelayExecutionThread(KernelMode, 0, &sleeptime); } PsTerminateSystemThread(STATUS_SUCCESS); } NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING RegPath) { HANDLE hThread = NULL; NTSTATUS status = NULL; UNICODE_STRING DeviceName = { 0 }; driverObject->DriverUnload = Unload; status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, CheckVmWare, NULL); if (!NT_SUCCESS(status)) { DbgPrint("Create Thread Failed!\n"); return STATUS_UNSUCCESSFUL; } status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &pThreadObject, NULL); if (!NT_SUCCESS(status)) { DbgPrint("Cannot reference"); ObDereferenceObject(pThreadObject); } RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDevices"); status = IoCreateDevice(driverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice); if (!NT_SUCCESS(status)) { DbgPrint("Create Device Failed!"); return STATUS_UNSUCCESSFUL; } RtlInitUnicodeString(&symLinkName, "\\?\\SybLinkName"); status = IoCreateSymbolicLink(&symLinkName, &DeviceName); if (!NT_SUCCESS(status)) { DbgPrint("Create SymLink Failed!"); //return STATUS_UNSUCCESSFUL; } IoInitializeTimer(pDevice, (PIO_TIMER_ROUTINE)TimerRoutine, NULL); IoStartTimer(pDevice); ZwClose(hThread); return STATUS_SUCCESS; }注:在X64下使用上文的汇编代码时,需要修改下asm的属性。效果: github:https://github.com/pcy190/DriverKit/tree/master/AntiVirtualMachine_driver
1 0 234天前
admin
889
jQuery自诞生以来,版本越来越多,而且jQuery官网的新版本还在不断的更新和发布中,现已经达到了2.x甚至更新的版本,但是我们在以前的项目中就已经使用了旧版本的jQuery,比如已经出现的:1.3.X、1.4.X、1.5.X、1.6.2等等。 由于项目的需要,必然也需要不断的使用较新版的jQuery,但对于原来就已经存在并已经采用了的旧jQuery版本,我们如何让多个不同的jQuery版本在同一个页面并存而不冲突呢? 其实,利用jQuery.noConflict()特性,我们不仅可以让jQuery与其他的JS库并存,比如Prototype。也可以与jQuery本身的其他不同版本并存而不冲突。<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>在同一个页面中加载多个不同的jQuery版本</title> <!-- 加载jQuery最新版本--> <script type="text/javascript" src="http://api.csource.com.cn/index.php?dir=&file=jquery-3.3.1.min.js"></script> <script type="text/javascript">var jQuery_New = $.noConflict(true);</script> <!-- 加载jQuery1.6.2版本--> <script type="text/javascript" src="http://api.csource.com.cn/index.php?dir=&file=jquery-1.6.2.min.js"></script> <script type="text/javascript">var jQuery_1_6_2 = $.noConflict(true);</script> <!-- 加载jQuery1.5.2版本--> <script type="text/javascript" src="http://api.csource.com.cn/index.php?dir=&file=jquery-1.5.2.min.js"></script> <script type="text/javascript">var jQuery_1_5_2 = $.noConflict(true);</script> <!-- 加载jQuery1.4.2版本--> <script type="text/javascript" src="http://api.csource.com.cn/index.php?dir=&file=jquery-1.4.2.min.js"></script> <script type="text/javascript">var jQuery_1_4_2 = $.noConflict(true);</script> <!-- 加载jQuery1.3.2版本--> <script type="text/javascript" src="http://api.csource.com.cn/index.php?dir=&file=jquery-1.3.2.min.js"></script> <script type="text/javascript">var jQuery_1_3_2 = $.noConflict(true);</script> <!-- 测试效果 --> <script type="text/javascript"> alert(jQuery_New.fn.jquery); alert(jQuery_1_6_2.fn.jquery); alert(jQuery_1_5_2.fn.jquery); alert(jQuery_1_4_2.fn.jquery); alert(jQuery_1_3_2.fn.jquery); jQuery_New(function($){$('<p>我是最新的'+$.fn.jquery+'版本添加进来的。</p>').appendTo('body');}); jQuery_1_6_2(function($){$('<p>我是'+$.fn.jquery+'版本添加进来的。</p>').appendTo('body');}); jQuery_1_5_2(function($){$('<p>我是'+$.fn.jquery+'版本添加进来的。</p>').appendTo('body');}); jQuery_1_4_2(function($){$('<p>我是'+$.fn.jquery+'版本添加进来的。</p>').appendTo('body');}); jQuery_1_3_2(function($){$('<p>我是'+$.fn.jquery+'版本添加进来的。</p>').appendTo('body');}); </script> </head> <body> 在同一个页面中加载多个不同的jQuery版本 <br> </body> </html>文件所用jsquery均可在:http://api.csource.com.cn/ 获取
1 0 274天前
admin
1752
原文地址:https://bbs.pediy.com/thread-225175.htm今天我们探索一个问题: 64位的ntdll是如何被加载到WoW64下的32位进程?今天的旅程将会带领我们进入到Windows内核逻辑中的未知领域,我们将会发现32位进程的内存地址空间是如何被初始化的。WoW64是什么?来自MSDN:WOW64是允许32位Windows应用程序无缝运行在64位Windows的模拟器。  换句话说,随着64位版本Windows的引进,Microsoft需要拿出一种允许在32位时代的Windows程序与64位Windows新的底层组件无缝交互的解决方案。特别是64位内存寻址和与内核直接交流的组件。两个NT层,一个内核在32位的Windows系统中,要调用Windows API的应用程序需要经过一系列的动态链接库(DLL)。然而,所有的系统调用最终会定向到ntdll.dll,它是在用户模式下将用户模式API传递给内核的最高层。以调用CreateFileW为例,这个API调用源于用户模式下的kernel32.dl,随后它以NtCreateFile传递给ntdll,随后NtCreateFile通过系统调度程序将控制权传递给内核。在32位Windows下这是非常简单的,然而,在WoW64下需要额外的步骤。32位的ntdll不可以直接将控制权交给内核,因为内核是64位的,只接受遵循64位ABI的类型(译者注:ABI,Application Binary Interface,应用二进制接口)。正因为如此,一个翻译层以几个标准的命名为wow64.dll,wow64cpu.dll和wow64win.dll的DLL的形式被添加到64位Windows。这几个DLL负责将32位调用转换成64位调用。那些调用最终被定向到映射到每个32位进程中的64位ntdll。许多关于这种从32位系统调用到64位系统调用(1)的神奇转换的信息是可获得的,所以我们不会从这里进入。我们最关注的是内核何时和怎样将64位版本的ntdll映射到一个32位进程。看起来像这样:我们特别关注倒数第二项。我们能发现ntdll被映射到地址是64位地址范围(7FFFFED40000-7FFFFEF1FFFF),而且它的位置在Windows 64位系统文件所在的System32\路径下。然而,我们知道32位进程不可以访问或者运行在64位内存空间。为了理解上面输出的内容,我们首先讨论VAD(Virtual Address Descriptor,虚拟地址描述符)是什么和它将如何帮助我们理解加载64位dll到32位进程的机制的。什么是虚拟地址描述符?VAD是Windows操作系统跟踪系统中可用物理内存的许多方法之一。VAD专门跟踪每个进程用户模式范围的保留的和提交的地址。任何时候一个进程请求一些内存,一个新的VAD实力被创建用来跟踪内存。VAD被构造成一个自平衡树,每个节点描述了一段内存范围。每个节点至多包含两个子节点,左边是低地址,右边是高地址。每个进程被分配一个VadRoot,之后通过遍历VadRoot来分辨额外用来描述保留或提交的虚拟地址范围的额外节点。我们需要关注WindDBG中的!vad命令的输出,因为这是我们将大量使用来跟踪64位Windows中32位进程的映射的输出。对于这个练习,不是所有的域对我们来说都是特别有趣的。我们考虑测试程序HelloWorld.exe的输出。通过!process ProcessObject 命令的输出来分辨我们进程的VadRoot。 一旦我们确定了VadRoot,我将地址输入到 !vad 命令。(输出为了容易分析已被截断)我们看到五列: "VAD", "Level", "Start", "End", 和"Commit".!vad命令 接受VAD实例的地址;在我们的例子中,我们已经为它提供了在此进程中通过使用!process命令获得的VadRoot。VAD地址是当前VAD结构体或实例的地址:等级(Level)描述了这个VAD实例(节点)在所在树中的级别。Level 0是从上面!process输出中获得的VadRoot。开始(Starting)和结束(Ending)地址值用VPN(Virtual Page Numbers,虚拟页数量)表示。这些地址可以通过乘以页面大小(4kb)或者左移3位转化为虚拟地址。结束VPN会添加一个额外的0xFFF来扩展到页面末尾。如我们上面例子中的D20->D20000,DD20->DD2FFF。提交(Commit)是被此VAD实例描述的范围内提交页面的数量。分配类型(type of allocation)告诉我们改特定范围是否已经被映射或是进程私有的。访问类型(Type of access)描述改范围内的允许访问。最后是被映射到当前区域对应的名称。一个AVD实例可以以多种方式创建。如通过使用映射API(CreateFileMapping/MapViewOfFile)或者内存分配API如VirutalAlloc函数。内存可以是保留或者提交的(或free的),或保留和部分提交的。无论哪一种,一个VAD项被映射到进程的Vad树来让内存管理器知道此进程中当前已提交的内存。我们对VAD 的观察将揭示WoW64下运行的32位进程的初始设置。  映射NT子系统DLL进程初始化的早期,在主可执行文件被映射和初始化之前,Windows为特殊区域确定和保留一些地址范围。其中包含初始进程地址空间,共享系统空间(_KUSER_SHARED_DATA),控制流守护位图区域,和NT本地子系统(ntdll)。由于进程初始化整体的复杂性,我们只关注最后一块,它包含32位ntdll和64位ntdll加载到32位进程地址空间的逻辑。我们关注一系列的API调用和在每个点的内存区域的虚拟地址描述符(VAD)。为了让内核区分怎样映射一个新进程,它需要知道是否这是一个WoW64进程。当进程对象最初被创建,内核通过读取名为_EPROCESS.Wow64Process的未文档化结构体_EPROCESS结构体的值来实现此操作。PspAllocateProcess是我们探索开始的地方,但是更具体的说,我们开始在MmInitializeProcessAddressSpace()。MmInitializeProcessAddressSpace()负责与一个新进程地址空间有关的初始化。它调用MiMapProcessExecutable,该函数创建了定义初始进程可寻址内存空间的VAD项,随后将新创建的进程映射到它的基虚拟地址。一个特别有趣的函数是PspMapSystemDlls。我们关注在调用PspMapSystemDlls之前的进程地址空间的样子。在WinDBG中确保我们当前处于我们测试应用程序的上下文中(.process),并寻找当前VadRoot(!vad output)。          到目前为止我们可以观察到,我们的进程在32问地址空间中被映射和分配了一个基地址(1200),内核共享内存(0x7FFE0000-0x7FFE0FFF) 和64KB保留内存区域(0x7FFE1000-0x7FFEFFFF) 也已经被映射到他们各自的虚拟地址。PspMapSystemDlls 通过一个包含多个平台子系统模块的全局指针迭代。对于x86和x64Windows,这些是分别位于 C:\Windows\SysWow64 和C:\Windows\System 目录中的ntdll.dll。一旦 PspMapSystemDlls 发现要加载的DLL,它调用 PspMapSystemDll 来映射他们(DLLs)到进程的地址空间。该函数非常简短,下面展示了一个片段。为了正确映射本地子系统,需要满足一些条件。         PspMapSystemDll 通过调用 MmMapViewOfSection 实现实际的本地DLL的映射,并保存所占的基地址。在这两个DLL映射完成并且他们的VAD项初始化完成后,我们的32位进程地址空间看起来像这样:             所以现在,我们映射完我们的进程(0xc40000-0xcf2fff),内核共享内存空间(0x7ffe0000-0x7ffe0fff),32位地址空间的有效结束区域(0x7ffe1000-0x7ffeffff),和我们的两个NT子系统DLL。锁定地址空间为了完成32位进程的映射,还有最后一步要做。我们知道一个32位进程最多寻址到2GB的虚拟内存,所以Windows需要屏蔽此进程剩余的地址空间。对于32位进程,屏蔽在 0x7FFF0000 - 0x7FFFFFFF 之后;然而,0x7FFeFFFF 之后什么也不可以映射。基于此事实,紧邻64位NTDLL的内存区域需要保留或者屏蔽。要做到这一点,内核标记剩下的64位地址空间为私有。它通过遍历当前进程的VAD树和定位最后可用的虚拟地址来创建此VAD项,然后附加一个新的VAD项。完成此任务的API是 MiInitializeUserNoAccess。该函数接受当前进程句柄和一个虚拟地址。传递的虚拟地址是 0x7FFF0000,这是32为进程最后可寻址范围的起始。然后,它遍历当前的VAD项并执行一个新范围的插入,该范围覆盖了32位进程剩余的地址空间。在此调用后,我们的进程地址空间看起来像这样:      我们现在可以发现,我们的32位进程已经映射,并且它的合规的内存地址范围已经被内核保留。涵盖 0x7FFF0 - 0x7FFFFED3F 和 0x7FFFFEF20- 0x7FFFFFFEF 范围的VAD实例已经被内核保留为私有。随后任何检索内存的调用仅仅会发生在允许的32为地址空间内。一旦进程完全加载,我们可以看到额外的已提交的内存出现在进程(0xC40000)附近的地址空间。       结束演讲我们观察到64位Windows下的32位进程的初始映射以及64位ntdll如何被映射到64位区域,随后64位地址空间被锁定,防止用户访问,我们学到了什么?1、早期初始化逻辑决定我们是否准备映射一个WoW64进程。2、分配最初的32位地址空间区域;这包括最高可访问的32位地址范围,和进程首选的基虚拟地址。3、NT子系统DLL被加载到他们各自的地址范围,32位ntdll加载到32位空间,64位ntdll加载到64位地址空间。4、MmInitializeUserNoAccess 用来创建与64位ntdll范围相邻的西游范围。这具有从32位进程锁定64位可寻址空间的效果。希望这篇文章提供了一些关于Windows如何允许讲32位进程无缝集成到64位Windows操作系统的透明度。随着WoW64模拟层的添加,对地址空间可用性进行了一些额外的考虑,并且这个过程反映了一些这些考虑和及其实现。 
1 0 586天前
admin
1844
DBA操作规范作者:hcymysql  原文转自:http://blog.51cto.com/hcymysql/20614511、涉及业务上的修改/删除数据,在得到业务方、CTO的邮件批准后方可执行,执行前提前做好备份,必要时可逆。2、所有上线需求必须走工单系统,口头通知视为无效。3、在对大表做表结构变更时,如修改字段属性会造成锁表,并会造成从库延迟,从而影响线上业务,必须在凌晨0:00 后业务低峰期执行,另统一用工具 pt-online-schema-change 避免锁表且降低延迟执行时间。使用范例:#pt-online-schema-change --alter="add index IX_id_no(id_no)" \ --no-check-replication-filters --recursion-method=none --user=dba \ --password=123456 D=test,t=t1 --execute对于MongoDB创建索引要在后台创建,避免锁表。使用范例:db.t1.createIndex({idCardNum:1},{background:1})4、所有线上业务库均必须搭建MHA高可用架构,避免单点问题。5、给业务方开权限时,密码要用MD5加密,至少16位。权限如没有特殊要求,均为select查询权限,并做库表级限制。6、删除默认空密码账号。delete from mysql.user where user='' and password=''; flush privileges;7、汇总库开启Audit审计日志功能,出现问题时方可追溯。行为规范8、禁止一个MySQL实例存放多个业务数据库,会造成业务耦合性过高,一旦出现问题会殃及池鱼,增加了定位故障问题的难度。通常采用多实例解决,一个实例一个业务库,互不干扰。9、禁止在主库上执行后台管理和统计类的功能查询,这种复杂类的SQL会造成CPU的升高,进而会影响业务。10、批量清洗数据,需要开发和DBA共同进行审查,应避开业务高峰期时段执行,并在执行过程中观察服务状态。11、促销活动等应提前与DBA当面沟通,进行流量评估,比如提前一周增加机器内存或扩展架构,防止DB出现性能瓶颈。12、禁止在线上做数据库压力测试。基本规范13、禁止在数据库中存储明文密码。14、使用InnoDB存储引擎。支持事务,行级锁,更好的恢复性,高并发下性能更好。InnoDB表避免使用COUNT(*)操作,因内部没有计数器,需要一行一行累加计算,计数统计实时要求较强可以使用memcache或者Redis。15、表字符集统一使用UTF8。不会产生乱码风险。16、所有表和字段都需要添加中文注释。方便他人、方便自己。17、不在数据库中存储图片、文件等大数据。图片、文件更适合于GFS分布式文件系统,数据库里存放超链接即可。18、避免使用存储过程、视图、触发器、事件。MySQL是OLTP应用,最擅长简单的增、删、改、查操作,但对逻辑计算分析类的应用,并不适合,所以这部分的需求最好通过程序上实现。19、避免使用外键,外键用来保护参照完整性,可在业务端实现。外键会导致父表和子表之间耦合,十分影响SQL性能,出现过多的锁等待,甚至会造成死锁。20、对事务一致性要求不高的业务,如日志表等,优先选择存入MongoDB。其自身支持的sharding分片功能,增强了横向扩展的能力,开发不用过多调整业务代码。库表设计规范21、表必须有主键,例如自增主键。这样可以保证数据行是按照顺序写入,对于SAS传统机械式硬盘写入性能更好,根据主键做关联查询的性能也会更好,并且还方便了数据仓库抽取数据。从性能的角度来说,使用UUID作为主键是个最不好的方法,它会使插入变得随机。22、禁止使用分区表。分区表的好处是对于开发来说,不用修改代码,通过后端DB的设置,比如对于时间字段做拆分,就可以轻松实现表的拆分。但这里面涉及一个问题,查询的字段必须是分区键,否则会遍历所有的分区表,并不会带来性能上的提升。此外,分区表在物理结构上仍旧是一张表,此时我们更改表结构,一样不会带来性能上的提升。所以应采用切表的形式做拆分,如程序上需要对历史数据做查询,可通过union all的方式关联查询。另外随着时间的推移,历史数据表不再需要,只需在从库上dump出来,即便捷地迁移至备份机上。字段设计规范23、用DECIMAL代替FLOAT和DOUBLE存储精确浮点数。浮点数的缺点是会引起精度问题,请看下面一个例子:mysql> CREATE TABLE t3 (c1 float(10,2),c2 decimal(10,2)); Query OK, 0 rows affected (0.05 sec) >mysql> insert into t3 values (999998.02, 999998.02); Query OK, 1 row affected (0.01 sec) >mysql> select * from t3; +-----------+-----------+ | c1 | c2 | +-----------+-----------+ | 999998.00 | 999998.02 | +-----------+-----------+ 1 row in set (0.00 sec)可以看到c1列的值由999998.02变成了999998.00,这就是float浮点数类型的不精确性造成的。因此对货币等对精度敏感的数据,应该用定点数表示或存储。24、使用TINYINT来代替ENUM类型。采用enum枚举类型,会存在扩展的问题,例如用户在线状态,如果此时增加了:5表示请勿打扰、6表示开会中、7表示隐身对好友可见,那么增加新的ENUM值要做DDL修改表结构操作了。25、字段长度尽量按实际需要进行分配,不要随意分配一个很大的容量。选择字段的一般原则是保小不保大,能用占用字节少的字段就不用大字段。比如主键,强烈建议用int整型,不用uuid,为什么?省空间啊。空间是什么?空间就是效率!按4个字节和按32个字节定位一条记录,谁快谁慢太明显了。涉及几个表做join时,效果就更明显了。更小的字段类型占用的内存就更少,占用的磁盘空间和磁盘I/O也会更少,而且还会占用更少的带宽。有不少开发人员在设计表字段时,只要是针对数值类型的全部用int,但这不一定合适,就比如用户的年龄,一般来说,年龄大都在1~100岁之间,长度只有3,那么用int就不适合了,可以用tinyint代替。又比如用户在线状态,0表示离线、1表示在线、2表示离开、3表示忙碌、4表示隐身等,其实类似这样的情况,用int都是没有必要的,浪费空间,采用tinyint完全可以满足需要,int占用的是4字节,而tinyint才占用1个字节。int整型有符号(signed)最大值是2147483647,而无符号(unsigned)最大值是4294967295,如果你的需求没有存储负数,那么建议改成有符号(unsigned),可以增加int存储范围。int(10)和int(1)没有什么区别,10和1仅是宽度而已,在设置了zerofill扩展属性的时候有用,例:root@localhost(test)10:39>create table test(id int(10) zerofill,id2 int(1)); Query OK, 0 rows affected (0.13 sec) root@localhost(test)10:39>insert into test values(1,1); Query OK, 1 row affected (0.04 sec) root@localhost(test)10:56>insert into test values(1000000000,1000000000); Query OK, 1 row affected (0.05 sec) root@localhost(test)10:56>select * from test; +------------+------------+ | id | id2 | +------------+------------+ | 0000000001 | 1 | | 1000000000 | 1000000000 | +------------+------------+ 2 rows in set (0.01 sec)26、字段定义为NOT NULL要提供默认值。从应用层角度来看,可以减少程序判断代码,比如你要查询一条记录,如果没默认值,你是不是得先判断该字段对应变量是否被设置,如果没有,你得通过java把该变量置为''或者0,如果设了默认值,判断条件可直接略过。NULL值很难进行查询优化,它会使索引统计更加复杂,还需要MySQL内部进行特殊处理。27、尽可能不使用TEXT、BLOB类型。增加存储空间的占用,读取速度慢。索引规范28、索引不是越多越好,按实际需要进行创建。索引是一把双刃剑,它可以提高查询效率但也会降低插入和更新的速度并占用磁盘空间。适当的索引对应用的性能至关重要,而且在MySQL中使用索引它的速度是极快的。遗憾的是,索引也有相关的开销。每次向表中写入时(如INSERT、UPDATEH或DELETE),如果带有一个或多个索引,那么MySQL也要更新各个索引,这样索引就增加了对各个表的写入操作的开销。只有当某列被用于WHERE子句时,才能享受到索引的性能提升的好处。如果不使用索引,它就没有价值,而且会带来维护上的开销。29、查询的字段必须创建索引。如:1、SELECT、UPDATE、DELETE语句的WHERE条件列;2、多表JOIN的字段。30、不在索引列进行数学运算和函数运算。无法使用索引,导致全表扫描。例:SELECT * FROM t WHERE YEAR(d) &gt;= 2016;由于MySQL不像Oracle那样支持函数索引,即使d字段有索引,也会直接全表扫描。应改为----->SELECT * FROM t WHERE d &gt;= '2016-01-01';31、不在低基数列上建立索引,例如‘性别’。有时候,进行全表浏览要比必须读取索引和数据表更快,尤其是当索引包含的是平均分布的数据集是更是如此。对此典型的例子是性别,它有两个均匀分布的值(男和女)。通过性别需要读取大概一半的行。在种情况下进行全表扫描浏览要更快。32、不使用%前导的查询,如like ‘%xxx’。无法使用索引,导致全表扫描。低效查询 SELECT * FROM t WHERE name LIKE '%de%'; -----> 高效查询 SELECT * FROM t WHERE name LIKE 'de%';33、不使用反向查询,如 not in / not like。无法使用索引,导致全表扫描。34、避免冗余或重复索引。联合索引IX_a_b_c(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),那么索引 (a) 、(a,b) 就是多余的。SQL设计规范*35、不使用SELECT ,只获取必要的字段。**消耗CPU和IO、消耗网络带宽;无法使用覆盖索引。36、用IN来替换OR。低效查询 SELECT * FROM t WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30; -----> 高效查询 SELECT * FROM t WHERE LOC_IN IN (10,20,30);37、避免数据类型不一致。SELECT * FROM t WHERE id = '19'; -----> SELECT * FROM t WHERE id = 19;38、减少与数据库的交互次数。INSERT INTO t (id, name) VALUES(1,'Bea'); INSERT INTO t (id, name) VALUES(2,'Belle'); INSERT INTO t (id, name) VALUES(3,'Bernice'); -----> INSERT INTO t (id, name) VALUES(1,'Bea'), (2,'Belle'),(3,'Bernice'); Update … where id in (1,2,3,4); Alter table tbl_name add column col1, add column col2;39、拒绝大SQL,拆分成小SQL。低效查询 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id = tag.id JOIN post ON tag_post.post_id = post.id WHERE tag.tag = 'mysql'; 可以分解成下面这些查询来代替 -----> 高效查询 SELECT * FROM tag WHERE tag = 'mysql' SELECT * FROM tag_post WHERE tag_id = 1234 SELECT * FROM post WHERE post_id in (123, 456, 567, 9098, 8904);40、禁止使用order by rand()SELECT * FROM t1 WHERE 1=1 ORDER BY RAND() LIMIT 4; ----> SELECT * FROM t1 WHERE id >= CEIL(RAND()*1000) LIMIT 4;
1 0 639天前
admin
1852
作者:Ox9A82    转自看雪论坛   原文地址:http://mp.weixin.qq.com/s/8lXtiwq5BO6PeXlFT57R7gQJavascript语言现在变得越来越流行,各个团队利用了它在各种层面上的支持特性,比如前端、后端、混合的应用程序、嵌入式设备等等。 这篇文章作为这一系列文章的第一篇,旨在深挖 Javascript 的底层工作原理:我们认为通过了解 Javascript 的构建块以及了解它们是怎么一起工作的可以使得我们写出更好的代码和app。我们还将分享构建 SessionStack 时的一些经验法则,这是一个轻量级的 JavaScript 应用程序,它必须保持强大且高性能才能保持竞争力。 如GitHut统计中所示,JavaScript在GitHub中的活动存储库和总推送量方面位居前列。相比其他类别也不落后。如果项目越来越依赖于JavaScript,这意味着开发人员必须利用语言和生态系统提供的所有内容,深入了解内部,才能构建出令人惊叹的软件。 事实证明,有很多开发人员每天都在使用JavaScript,但并不知道底层会发生什么。概览几乎每个人都听说过V8引擎这个概念,大多数人都知道JavaScript是单线程的,或者它使用的是回调队列。在这篇文章中,我们将详细介绍所有这些概念,并解释JavaScript如何运行。通过了解这些细节,您将能够编写更好的非阻塞应用程序,并且学会正确使用所提供的API。 如果你对JavaScript比较陌生,那么这篇博文将帮助你理解为什么说JavaScript与其他语言相比是比较怪异的。 如果你是一位经验丰富的JavaScript开发人员,我希望能够提供一些关于你每天都在使用的JavaScript Runtime的实际工作情况的全新理解。Javascript引擎关于JS引擎一个最著名的例子就是谷歌的V8引擎。目前Chrome和Node.js中使用的就是V8引擎。下面是一个简单的视图:引擎包含两个主要部件:堆内存 - 这是发生内存分配的地方调用栈 - 这是代码执行时的栈帧运行时几乎所有的JS开发者在浏览器中都使用过API(例如“setTimeout”)。但是,这些API不是由引擎提供的。 那么这些API从哪里来呢? 事实证明,现实情况有些复杂。如图所示,可以发现其实我们除了引擎之外还依赖其他很多东西。像DOM、AJAX、setTimeout等等这些东西是由浏览器提供的,被称为Web API。 然后,我们就有了非常流行的事件循环和回调队列。调用栈JavaScript是一种单线程语言,这意味着它只有一个调用栈。因此,它同一时间只可以做一件事。调用栈是一个数据结构,它大致的记录了我们位于程序中的哪个位置。 如果我们进入一个函数,就会把它放在栈的顶部。如果我们从一个函数返回,那么会弹出栈的顶部。 我们来看一个例子。如下面的代码:function multiply(x, y) { return x * y; } function printSquare(x) { var s = multiply(x, x); console.log(s); } printSquare(5);当引擎开始执行这段代码之前,调用栈是空的。之后的步骤如下:调用栈中的每个条目都称为是栈帧。 这也是在发生异常时进行堆栈跟踪的方法 - 这大体上是异常发生时的调用栈的状态。看看下面的代码:function foo() { throw new Error('SessionStack will help you resolve crashes :)'); } function bar() { foo(); } function start() { bar(); } start();如果这是在Chrome中执行的(假设代码在一个名为foo.js的文件中),那么会产生下面的堆栈跟踪:“栈上溢(Blowing the stack)” - 当达到最大调用栈大小时就会发生这种情况。 这可能会很容易的发生,特别是使用递归的情况下。看看这个示例代码:function foo() { foo(); } foo();当引擎开始执行这个代码时,它首先调用函数“foo”。然而,这个函数是递归的,并且没有任何终止条件。 所以在执行的步骤中,同一个函数会一次又一次地添加到调用栈中。 它看起来像这样:在某些情况下,调用栈中函数调用的数量超出了调用栈的实际大小,浏览器通过抛出一个错误(如下所示)来采取行动:在单线程上运行代码可能会更容易一些,因为不必担心多线程环境中出现的复杂场景,例如死锁。 但是在单线程上运行也是非常有限的。 由于JS只有一个调用栈,所以当运行很慢时会发生什么?并发和事件循环如果在调用栈中的函数调用需要花费大量时间才能进行处理,会发生什么? 例如,假设你想在浏览器中使用JS进行一些复杂的图像转换。 你可能会奇怪 - 为什么这是个问题?但是问题是,虽然调用栈有执行的功能,但此时浏览器实际上不能做其他的任何事情 - 它被阻塞了。 这意味着浏览器无法进行渲染,也不能运行任何其他代码,它只是卡住了。 如果你想在你的应用程序中实现流畅的UI,这就会产生问题。 并且这还不是唯一的问题。 一旦浏览器开始在调用栈中处理如此多的任务,它可能会停止响应相当长的时间。 而且大多数浏览器会通过抛出错误来应对,询问是否要终止网页。所以这不是一个好的用户体验,是吗? 那么,我们如何执行大量代码而不会阻塞UI使浏览器无法响应呢?解决方案是异步回调。这将在“JavaScript底层是如何工作的”教程的第2部分中更详细地解释。 同时,如果在JS应用遇到了难以复制和理解问题,请查看SessionStack。 SessionStack记录Web应用程序中的所有内容:所有的DOM更改,用户交互,JavaScript异常,堆栈跟踪,失败的网络请求和调试消息。借助SessionStack,可以将视频中的问题重放为视频,并查看用户发生的所有事情。
2 0 643天前
admin
1531
一、什么是CURL?cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP、FTP、TELNET等。最爽的是,PHP也支持 cURL 库。使用PHP的cURL库可以简单和有效地去抓网页。你只需要运行一个脚本,然后分析一下你所抓取的网页,然后就可以以程序的方式得到你想要的数据了。无论是你想从从一个链接上取部分数据,或是取一个XML文件并把其导入数据库,那怕就是简单的获取网页内容,cURL 是一个功能强大的PHP库。二、CURL函数库。curl_close — 关闭一个curl会话curl_copy_handle — 拷贝一个curl连接资源的所有内容和参数curl_errno — 返回一个包含当前会话错误信息的数字编号curl_error — 返回一个包含当前会话错误信息的字符串curl_exec — 执行一个curl会话curl_getinfo — 获取一个curl连接资源句柄的信息curl_init — 初始化一个curl会话curl_multi_add_handle — 向curl批处理会话中添加单独的curl句柄资源curl_multi_close — 关闭一个批处理句柄资源curl_multi_exec — 解析一个curl批处理句柄curl_multi_getcontent — 返回获取的输出的文本流curl_multi_info_read — 获取当前解析的curl的相关传输信息curl_multi_init — 初始化一个curl批处理句柄资源curl_multi_remove_handle — 移除curl批处理句柄资源中的某个句柄资源curl_multi_select — Get all the sockets associated with the cURL extension, which can then be “selected”curl_setopt_array — 以数组的形式为一个curl设置会话参数curl_setopt — 为一个curl设置会话参数curl_version — 获取curl相关的版本信息curl_init()函数的作用初始化一个curl会话,curl_init()函数唯一的一个参数是可选的,表示一个url地址。curl_exec()函数的作用是执行一个curl会话,唯一的参数是curl_init()函数返回的句柄。curl_close()函数的作用是关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄。三、PHP建立CURL请求的基本步骤①:初始化curl_init()②:设置属性curl_setopt().有一长串cURL参数可供设置,它们能指定URL请求的各个细节。③:执行并获取结果curl_exec()④:释放句柄curl_close()四、CURL实现GET和POST①:GET方式实现<?php //初始化 $curl = curl_init(); //设置抓取的url curl_setopt($curl, CURLOPT_URL, 'http://www.baidu.com'); //设置头文件的信息作为数据流输出 curl_setopt($curl, CURLOPT_HEADER, 1); //设置获取的信息以文件流的形式返回,而不是直接输出。 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //执行命令 $data = curl_exec($curl); //关闭URL请求 curl_close($curl); //显示获得的数据 print_r($data); ?>运行结果:②:POST方式实现<?php //初始化 $curl = curl_init(); //设置抓取的url curl_setopt($curl, CURLOPT_URL, 'http://www.baidu.com'); //设置头文件的信息作为数据流输出 curl_setopt($curl, CURLOPT_HEADER, 1); //设置获取的信息以文件流的形式返回,而不是直接输出。 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //设置post方式提交 curl_setopt($curl, CURLOPT_POST, 1); //设置post数据 $post_data = array( "username" => "coder", "password" => "12345" ); curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data); //执行命令 $data = curl_exec($curl); //关闭URL请求 curl_close($curl); //显示获得的数据 print_r($data); ?>③:如果获得的数据时json格式的,使用json_decode函数解释成数组。$output_array = json_decode($output,true);如果使用json_decode($output)解析的话,将会得到object类型的数据。五、我自己封装的一个函数//参数1:访问的URL,参数2:post数据(不填则为GET),参数3:提交的$cookies,参数4:是否返回$cookies function curl_request($url,$post='',$cookie='', $returnCookie=0){ $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($curl, CURLOPT_AUTOREFERER, 1); curl_setopt($curl, CURLOPT_REFERER, "http://XXX"); if($post) { curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post)); } if($cookie) { curl_setopt($curl, CURLOPT_COOKIE, $cookie); } curl_setopt($curl, CURLOPT_HEADER, $returnCookie); curl_setopt($curl, CURLOPT_TIMEOUT, 10); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $data = curl_exec($curl); if (curl_errno($curl)) { return curl_error($curl); } curl_close($curl); if($returnCookie){ list($header, $body) = explode("\r\n\r\n", $data, 2); preg_match_all("/Set\-Cookie:([^;]*);/", $header, $matches); $info['cookie'] = substr($matches[1][0], 1); $info['content'] = $body; return $info; }else{ return $data; } }附可选参数说明:第一类:对于下面的这些option的可选参数,value应该被设置一个bool类型的值:选项可选value值备注CURLOPT_AUTOREFERER当根据Location:重定向时,自动设置header中的Referer:信息。CURLOPT_BINARYTRANSFER在启用CURLOPT_RETURNTRANSFER的时候,返回原生的(Raw)输出。CURLOPT_COOKIESESSION启用时curl会仅仅传递一个session cookie,忽略其他的cookie,默认状况下cURL会将所有的cookie返回给服务端。session cookie是指那些用来判断服务器端的session是否有效而存在的cookie。CURLOPT_CRLF启用时将Unix的换行符转换成回车换行符。CURLOPT_DNS_USE_GLOBAL_CACHE启用时会启用一个全局的DNS缓存,此项为线程安全的,并且默认启用。CURLOPT_FAILONERROR显示HTTP状态码,默认行为是忽略编号小于等于400的HTTP信息。CURLOPT_FILETIME启用时会尝试修改远程文档中的信息。结果信息会通过 curl_getinfo()函数的CURLINFO_FILETIME选项返回。curl_getinfo().CURLOPT_FOLLOWLOCATION启用时会将服务器服务器返回的”Location: “放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。CURLOPT_FORBID_REUSE在完成交互以后强迫断开连接,不能重用。CURLOPT_FRESH_CONNECT强制获取一个新的连接,替代缓存中的连接。CURLOPT_FTP_USE_EPRT启用时当FTP下载时,使用EPRT (或 LPRT)命令。设置为FALSE时禁用EPRT和LPRT,使用PORT命令 only.CURLOPT_FTP_USE_EPSV启用时,在FTP传输过程中回复到PASV模式前首先尝试EPSV命令。设置为FALSE时禁用EPSV命令。CURLOPT_FTPAPPEND启用时追加写入文件而不是覆盖它。CURLOPT_FTPASCIICURLOPT_TRANSFERTEXT的别名。CURLOPT_FTPLISTONLY启用时只列出FTP目录的名字。CURLOPT_HEADER启用时会将头文件的信息作为数据流输出。CURLINFO_HEADER_OUT启用时追踪句柄的请求字符串。从 PHP 5.1.3 开始可用。CURLINFO_前缀是故意的(intentional)。CURLOPT_HTTPGET启用时会设置HTTP的method为GET,因为GET是默认是,所以只在被修改的情况下使用。CURLOPT_HTTPPROXYTUNNEL启用时会通过HTTP代理来传输。CURLOPT_MUTE启用时将cURL函数中所有修改过的参数恢复默认值。CURLOPT_NETRC在连接建立以后,访问~/.netrc文件获取用户名和密码信息连接远程站点。CURLOPT_NOBODY启用时将不对HTML中的BODY部分进行输出。CURLOPT_NOPROGRESS启用时关闭curl传输的进度条,此项的默认设置为启用。Note:PHP自动地设置这个选项为TRUE,这个选项仅仅应当在以调试为目的时被改变。CURLOPT_NOSIGNAL启用时忽略所有的curl传递给php进行的信号。在SAPI多线程传输时此项被默认启用。cURL 7.10时被加入。CURLOPT_POST启用时会发送一个常规的POST请求,类型为:application/x-www-form-urlencoded,就像表单提交的一样。CURLOPT_PUT启用时允许HTTP发送文件,必须同时设置CURLOPT_INFILE和CURLOPT_INFILESIZE。CURLOPT_RETURNTRANSFER将 curl_exec()获取的信息以文件流的形式返回,而不是直接输出。CURLOPT_SSL_VERIFYPEER禁用后cURL将终止从服务端进行验证。使用CURLOPT_CAINFO选项设置证书使用CURLOPT_CAPATH选项设置证书目录 如果CURLOPT_SSL_VERIFYPEER(默认值为2)被启用,CURLOPT_SSL_VERIFYHOST需要被设置成TRUE否则设置为FALSE。自cURL 7.10开始默认为TRUE。从cURL 7.10开始默认绑定安装。CURLOPT_TRANSFERTEXT启用后对FTP传输使用ASCII模式。对于LDAP,它检索纯文本信息而非HTML。在Windows系统上,系统不会把STDOUT设置成binary模式。CURLOPT_UNRESTRICTED_AUTH在使用CURLOPT_FOLLOWLOCATION产生的header中的多个locations中持续追加用户名和密码信息,即使域名已发生改变。CURLOPT_UPLOAD启用后允许文件上传。CURLOPT_VERBOSE启用时会汇报所有的信息,存放在STDERR或指定的CURLOPT_STDERR中。第二类:对于下面的这些option的可选参数,value应该被设置一个integer类型的值:选项可选value值备注CURLOPT_BUFFERSIZE每次获取的数据中读入缓存的大小,但是不保证这个值每次都会被填满。在cURL 7.10中被加入。CURLOPT_CLOSEPOLICY不是CURLCLOSEPOLICY_LEAST_RECENTLY_USED就是CURLCLOSEPOLICY_OLDEST,还存在另外三个CURLCLOSEPOLICY_,但是cURL暂时还不支持。CURLOPT_CONNECTTIMEOUT在发起连接前等待的时间,如果设置为0,则无限等待。CURLOPT_CONNECTTIMEOUT_MS尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。在cURL 7.16.2中被加入。从PHP 5.2.3开始可用。CURLOPT_DNS_CACHE_TIMEOUT设置在内存中保存DNS信息的时间,默认为120秒。CURLOPT_FTPSSLAUTHFTP验证方式:CURLFTPAUTH_SSL (首先尝试SSL),CURLFTPAUTH_TLS (首先尝试TLS)或CURLFTPAUTH_DEFAULT (让cURL自动决定)。在cURL 7.12.2中被加入。CURLOPT_HTTP_VERSIONCURL_HTTP_VERSION_NONE (默认值,让cURL自己判断使用哪个版本),CURL_HTTP_VERSION_1_0 (强制使用 HTTP/1.0)或CURL_HTTP_VERSION_1_1 (强制使用 HTTP/1.1)。CURLOPT_HTTPAUTH使用的HTTP验证方法,可选的值有:CURLAUTH_BASIC、CURLAUTH_DIGEST、CURLAUTH_GSSNEGOTIATE、CURLAUTH_NTLM、CURLAUTH_ANY和CURLAUTH_ANYSAFE。可以使用|位域(或)操作符分隔多个值,cURL让服务器选择一个支持最好的值。CURLAUTH_ANY等价于CURLAUTH_BASIC | CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM.CURLAUTH_ANYSAFE等价于CURLAUTH_DIGEST | CURLAUTH_GSSNEGOTIATE | CURLAUTH_NTLM.CURLOPT_INFILESIZE设定上传文件的大小限制,字节(byte)为单位。CURLOPT_LOW_SPEED_LIMIT当传输速度小于CURLOPT_LOW_SPEED_LIMIT时(bytes/sec),PHP会根据CURLOPT_LOW_SPEED_TIME来判断是否因太慢而取消传输。CURLOPT_LOW_SPEED_TIME当传输速度小于CURLOPT_LOW_SPEED_LIMIT时(bytes/sec),PHP会根据CURLOPT_LOW_SPEED_TIME来判断是否因太慢而取消传输。CURLOPT_MAXCONNECTS允许的最大连接数量,超过是会通过CURLOPT_CLOSEPOLICY决定应该停止哪些连接。CURLOPT_MAXREDIRS指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的。CURLOPT_PORT用来指定连接端口。(可选项)CURLOPT_PROTOCOLSCURLPROTO_*的位域指。如果被启用,位域值会限定libcurl在传输过程中有哪些可使用的协议。这将允许你在编译libcurl时支持众多协议,但是限制只是用它们中被允许使用的一个子集。默认libcurl将会使用全部它支持的协议。参见CURLOPT_REDIR_PROTOCOLS.可用的协议选项为:CURLPROTO_HTTP、CURLPROTO_HTTPS、CURLPROTO_FTP、CURLPROTO_FTPS、CURLPROTO_SCP、CURLPROTO_SFTP、CURLPROTO_TELNET、CURLPROTO_LDAP、CURLPROTO_LDAPS、CURLPROTO_DICT、CURLPROTO_FILE、CURLPROTO_TFTP、CURLPROTO_ALL在cURL 7.19.4中被加入。CURLOPT_PROXYAUTHHTTP代理连接的验证方式。使用在CURLOPT_HTTPAUTH中的位域标志来设置相应选项。对于代理验证只有CURLAUTH_BASIC和CURLAUTH_NTLM当前被支持。在cURL 7.10.7中被加入。CURLOPT_PROXYPORT代理服务器的端口。端口也可以在CURLOPT_PROXY中进行设置。CURLOPT_PROXYTYPE不是CURLPROXY_HTTP (默认值) 就是CURLPROXY_SOCKS5。在cURL 7.10中被加入。CURLOPT_REDIR_PROTOCOLSCURLPROTO_*中的位域值。如果被启用,位域值将会限制传输线程在CURLOPT_FOLLOWLOCATION开启时跟随某个重定向时可使用的协议。这将使你对重定向时限制传输线程使用被允许的协议子集默认libcurl将会允许除FILE和SCP之外的全部协议。这个和7.19.4预发布版本种无条件地跟随所有支持的协议有一些不同。关于协议常量,请参照CURLOPT_PROTOCOLS。在cURL 7.19.4中被加入。CURLOPT_RESUME_FROM在恢复传输时传递一个字节偏移量(用来断点续传)。CURLOPT_SSL_VERIFYHOST1 检查服务器SSL证书中是否存在一个公用名(common name)。译者注:公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。2 检查公用名是否存在,并且是否与提供的主机名匹配。CURLOPT_SSLVERSION使用的SSL版本(2 或 3)。默认情况下PHP会自己检测这个值,尽管有些情况下需要手动地进行设置。CURLOPT_TIMECONDITION如果在CURLOPT_TIMEVALUE指定的某个时间以后被编辑过,则使用CURL_TIMECOND_IFMODSINCE返回页面,如果没有被修改过,并且CURLOPT_HEADER为true,则返回一个”304 Not Modified”的header,        CURLOPT_HEADER为false,则使用CURL_TIMECOND_IFUNMODSINCE,默认值为CURL_TIMECOND_IFUNMODSINCE。CURLOPT_TIMEOUT设置cURL允许执行的最长秒数。CURLOPT_TIMEOUT_MS设置cURL允许执行的最长毫秒数。在cURL 7.16.2中被加入。从PHP 5.2.3起可使用。CURLOPT_TIMEVALUE设置一个CURLOPT_TIMECONDITION使用的时间戳,在默认状态下使用的是CURL_TIMECOND_IFMODSINCE。第三类:对于下面的这些option的可选参数,value应该被设置一个string类型的值:选项可选value值备注CURLOPT_CAINFO一个保存着1个或多个用来让服务端验证的证书的文件名。这个参数仅仅在和CURLOPT_SSL_VERIFYPEER一起使用时才有意义。 .CURLOPT_CAPATH一个保存着多个CA证书的目录。这个选项是和CURLOPT_SSL_VERIFYPEER一起使用的。CURLOPT_COOKIE设定HTTP请求中”Cookie: “部分的内容。多个cookie用分号分隔,分号后带一个空格(例如, “fruit=apple; colour=red”)。CURLOPT_COOKIEFILE包含cookie数据的文件名,cookie文件的格式可以是Netscape格式,或者只是纯HTTP头部信息存入文件。CURLOPT_COOKIEJAR连接结束后保存cookie信息的文件。CURLOPT_CUSTOMREQUEST使用一个自定义的请求信息来代替”GET”或”HEAD”作为HTTP请求。这对于执行”DELETE” 或者其他更隐蔽的HTTP请求。有效值如”GET”,”POST”,”CONNECT”等等。也就是说,不要在这里输入整个HTTP请求。例如输入”GET /index.html HTTP/1.0\r\n\r\n”是不正确的。Note:在确定服务器支持这个自定义请求的方法前不要使用。CURLOPT_EGDSOCKET类似CURLOPT_RANDOM_FILE,除了一个Entropy Gathering Daemon套接字。CURLOPT_ENCODINGHTTP请求头中”Accept-Encoding: “的值。支持的编码有”identity”,”deflate”和”gzip”。如果为空字符串””,请求头会发送所有支持的编码类型。在cURL 7.10中被加入。CURLOPT_FTPPORT这个值将被用来获取供FTP”POST”指令所需要的IP地址。”POST”指令告诉远程服务器连接到我们指定的IP地址。这个字符串可以是纯文本的IP地址、主机名、一个网络接口名(UNIX下)或者只是一个’-’来使用默认的IP地址。CURLOPT_INTERFACE网络发送接口名,可以是一个接口名、IP地址或者是一个主机名。CURLOPT_KRB4LEVELKRB4 (Kerberos 4) 安全级别。下面的任何值都是有效的(从低到高的顺序):”clear”、”safe”、”confidential”、”private”.。如果字符串和这些都不匹配,将使用”private”。这个选项设置为NULL时将禁用KRB4 安全认证。目前KRB4 安全认证只能用于FTP传输。CURLOPT_POSTFIELDS全部数据使用HTTP协议中的”POST”操作来发送。要发送文件,在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似’para1=val1¶2=val2&…’或使用一个以字段名为键值,字段数据为值的数组。如果value是一个数组,Content-Type头将会被设置成multipart/form-data。CURLOPT_PROXYHTTP代理通道。CURLOPT_PROXYUSERPWD一个用来连接到代理的”[username]:[password]“格式的字符串。CURLOPT_RANDOM_FILE一个被用来生成SSL随机数种子的文件名。CURLOPT_RANGE以”X-Y”的形式,其中X和Y都是可选项获取数据的范围,以字节计。HTTP传输线程也支持几个这样的重复项中间用逗号分隔如”X-Y,N-M”。CURLOPT_REFERER在HTTP请求头中”Referer: “的内容。CURLOPT_SSL_CIPHER_LIST一个SSL的加密算法列表。例如RC4-SHA和TLSv1都是可用的加密列表。CURLOPT_SSLCERT一个包含PEM格式证书的文件名。CURLOPT_SSLCERTPASSWD使用CURLOPT_SSLCERT证书需要的密码。CURLOPT_SSLCERTTYPE证书的类型。支持的格式有”PEM” (默认值), “DER”和”ENG”。在cURL 7.9.3中被加入。CURLOPT_SSLENGINE用来在CURLOPT_SSLKEY中指定的SSL私钥的加密引擎变量。CURLOPT_SSLENGINE_DEFAULT用来做非对称加密操作的变量。CURLOPT_SSLKEY包含SSL私钥的文件名。CURLOPT_SSLKEYPASSWD在CURLOPT_SSLKEY中指定了的SSL私钥的密码。Note:由于这个选项包含了敏感的密码信息,记得保证这个PHP脚本的安全。CURLOPT_SSLKEYTYPECURLOPT_SSLKEY中规定的私钥的加密类型,支持的密钥类型为”PEM”(默认值)、”DER”和”ENG”。CURLOPT_URL需要获取的URL地址,也可以在 curl_init()函数中设置。CURLOPT_USERAGENT在HTTP请求中包含一个”User-Agent: “头的字符串。CURLOPT_USERPWD传递一个连接中需要的用户名和密码,格式为:”[username]:[password]“。第四类对于下面的这些option的可选参数,value应该被设置一个数组:选项可选value值备注CURLOPT_HTTP200ALIASES200响应码数组,数组中的响应吗被认为是正确的响应,否则被认为是错误的。在cURL 7.10.3中被加入。CURLOPT_HTTPHEADER一个用来设置HTTP头字段的数组。使用如下的形式的数组进行设置: array(‘Content-type: text/plain’, ‘Content-length: 100′)CURLOPT_POSTQUOTE在FTP请求执行完成后,在服务器上执行的一组FTP命令。CURLOPT_QUOTE一组先于FTP请求的在服务器上执行的FTP命令。对于下面的这些option的可选参数,value应该被设置一个流资源 (例如使用 fopen()):选项可选value值CURLOPT_FILE设置输出文件的位置,值是一个资源类型,默认为STDOUT (浏览器)。CURLOPT_INFILE在上传文件的时候需要读取的文件地址,值是一个资源类型。CURLOPT_STDERR设置一个错误输出地址,值是一个资源类型,取代默认的STDERR。CURLOPT_WRITEHEADER设置header部分内容的写入的文件地址,值是一个资源类型。对于下面的这些option的可选参数,value应该被设置为一个回调函数名:选项可选value值CURLOPT_HEADERFUNCTION设置一个回调函数,这个函数有两个参数,第一个是cURL的资源句柄,第二个是输出的header数据。header数据的输出必须依赖这个函数,返回已写入的数据大小。CURLOPT_PASSWDFUNCTION设置一个回调函数,有三个参数,第一个是cURL的资源句柄,第二个是一个密码提示符,第三个参数是密码长度允许的最大值。返回密码的值。CURLOPT_PROGRESSFUNCTION设置一个回调函数,有三个参数,第一个是cURL的资源句柄,第二个是一个文件描述符资源,第三个是长度。返回包含的数据。CURLOPT_READFUNCTION拥有两个参数的回调函数,第一个是参数是会话句柄,第二是HTTP响应头信息的字符串。使用此函数,将自行处理返回的数据。返回值为数据大小,以字节计。返回0代表EOF信号。CURLOPT_WRITEFUNCTION拥有两个参数的回调函数,第一个是参数是会话句柄,第二是HTTP响应头信息的字符串。使用此回调函数,将自行处理响应头信息。响应头信息是整个字符串。设置返回值为精确的已写入字符串长度。发生错误时传输线程终止。本文链接:http://www.blogfshare.com/php-curl-get-post.html
1 0 647天前
admin
1835
原文地址:http://blog.csdn.net/ibingow/article/details/7104346 经常碰到某些程序崩溃时弹出带红色叉叉的错误窗口或者是叫你选择调试或关闭的窗口,很碍眼。不过平时也没去理它,点掉就好。    今天客户反映我们的程序崩溃后就起不来了,其实我们为了方便无人化管理,做了一个守护进程。如果程序异常退出就会重启那个程序,这在linux下没问题,程序崩溃了就直接退出返回非零值,但是window就bug了,搞不好就给你弹出个错误对话框,你不点掉其实程序就没退出,守护进程就不知道这个程序是否崩溃,于是这个程序就永远死在那个窗口上了。现在这不仅碍眼,还碍事!于是着手摆平之。    先是晚上搜到可以修改注册表来组织程序或系统的弹出对话框,参考:http://technet.microsoft.com/en-us/library/cc976167.aspx。不过这不可行,我们只是希望我们的程序不会弹出对话框,尽量少改系统的。而且试了下发现还是会弹出来,就是那个werfault.exe进程,xp下可能不会。算了,这条路不走了。    用代码肯定也有办法解决。你看人家qq什么的奔溃了有弹出的都是自家的温馨提示,我们不需要温馨提示,只要返回非零值就好。    万能的Google一下子就搜出结果来了。原来Microsoft对c和c++进行了扩展,支持异常处理,而且貌似标准c++里的异常处理也是它的一个封装。Microsoft的异常处理函数是__try,__except。先试了这么个简单的例子 #include <windows.h> #include <excpt.h> #include <stdio.h> #define CRASH_SILENTLY 1 #if defined(_MSC_VER) && CRASH_SILENTLY #include <excpt.h> #define Q_TRY_BEGIN __try { #define Q_TRY_END } //EXCEPTION_EXECUTE_HANDLER #define Q_EXCEPT __except(EXCEPTION_EXECUTE_HANDLER) { \ printf("Shit happens!\n");fflush(NULL); \ return 1;} #else #define Q_TRY_BEGIN #define Q_TRY_END #define Q_EXCEPT #endif int main(int, char**) { Q_TRY_BEGIN int *a = 0; *a = 0; Q_TRY_END Q_EXCEPT printf("Exiting 0...\n"); fflush(NULL); return 0; }     如果把CRASH_SILENTLY定义为0,那么在程序崩溃就会弹出对话框,设为一就只打印Shit happens!然后就返回。    __except的参数有三种,详细内容见http://msdn.microsoft.com/en-us/library/s58ftw19%28v=vs.80%29.aspx,我就不抄了。    其实为什么系统会弹出这么一个对话框呢?其实在vc运行库中顶层函数也用了__try, __except的异常捕获机制。不知您看了__except的参数了没,我的示例程序里是EXCEPTION_EXECUTE_HANDLER,表示异常被识别,就在__except后面的代码段进行异常处理。如果是EXCEPTION_CONTINUE_SEARCH,那么异常会继续被派发到外层,这最外层就是vc库,vc库它的处理手段就是碍眼又碍事的对话框!    上面这个程序只是演示用的,很简单。然后我就满怀希望地对公司的程序也做了类似的处理,然后悲剧发生了,竟然编译都通不过!编译错误是C2712:cannot use __try in functions that require object unwinding。于是又google了一番。msdn真的很棒,资料丰富,这下有时msdn上的方法解决的。详见http://msdn.microsoft.com/en-us/library/xwtb73ad%28VS.80%29.aspx    With /EHsc, a function with structured exception handling cannot have objects that require unwinding (destruction).    我们的程序里出现了有析构函数的对象,同时编译参数又有/EHsc,于是出现编译错误了。可以参考下这篇文章http://se.csai.cn/ExpertEyes/No163.htm    作为一个例子,如果我们把上面的程序改成下面的就可能出现上述问题class Shit { public: Shit() {} ~Shit() {} }; int main(int, char**) { Q_TRY_BEGIN Shit s; int *a = 0; *a = 0; Q_TRY_END Q_EXCEPT printf("Exiting 0...\n"); fflush(NULL); return 0; }     msdn提出3种方案,允许我复制下    Move code that requires SEH to another function.    Rewrite functions that use SEH to avoid the use of local variables and parameters that have destructors. Do not use SEH in constructors or destructors.    Compile without /EHsc.    显然前两种办法对代码改动太大了,不可取,那么就去掉/EHsc吧。由于我是用Qt写程序,有些编译选项都是默认设好的,我在pro文件里尝试定义QMAKE_CXXFLAGS竟然无效,不是很清楚为什么。一般是在qmake.config和prf文件里里可以找到。qmake.conf里找到相关的两行 QMAKE_CXXFLAGS_STL_ON = -EHsc QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc 在我们工程文件里直接设这两个为空竟然可以。后来又看了下Makefile,发现生成Makefile会依赖exceptions.prf, stl.prf,而这两个会加入上面两个变量,比如stl.prf:CONFIG -= stl_off QMAKE_CFLAGS *= $QMAKE_CFLAGS_STL_ON QMAKE_CXXFLAGS *= $QMAKE_CXXFLAGS_STL_ON 于是在工程文件中加入CONFIG -= exceptions stl 或者CONFIG += exceptions_off stl_off 就解决问题了,而且比之前的方法优雅。看看Makefile里相关代码变成了$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\default CONFIG+=release -o Makefile pvplayer.pro ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\qconfig.pri: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\modules\qt_webkit_version.pri: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt_functions.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt_config.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\exclusive_builds.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\default_pre.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\default_pre.prf: ..\config.pri: ..\pvcommon\pvcommon.pri: ..\config.pri: ..\log4qt\log4qt.pri: ..\config.pri: ..\qextserialport\qextserialport.pri: ..\config.pri: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\release.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\debug_and_release.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\default_post.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\default_post.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\rtti.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\shared.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\embed_manifest_exe.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\embed_manifest_dll.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\warn_on.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\thread.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\moc.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\windows.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\stl_off.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\exceptions_off.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\resources.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\uic.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\yacc.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\lex.prf: ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\incredibuild_xge.prf: e:\QtSDK\Desktop\Qt\4.7.4\msvc2008\lib\qtmain.prl:     好,至此已经把弹出对话框的问题解决了。不过还值得深入研究,目前只是做到了会用的程度。还有就是linux下或其他平台上有无类似处理还没调查。应该也有,因为最近linux下的thunderbird一启动就崩溃,弹出对话框。有空继续研究。参考文献:http://msdn.microsoft.com/en-us/library/s58ftw19%28v=vs.80%29.aspxhttp://msdn.microsoft.com/en-us/library/xwtb73ad%28VS.80%29.aspxUse /EHa if you want to catch an exception raised with something other than a throw.http://msdn.microsoft.com/en-us/library/1deeycx5%28VS.80%29.aspxhttp://blog.csdn.net/bichenggui/article/details/4536534http://se.csai.cn/ExpertEyes/No163.htm
1 0 647天前
admin
1770
原文转自:https://bbs.pediy.com/thread-221236.htm  作者:mrMORE Windows操作系统作为PC上最普及的操作系统,面向的用户各种各样,因此在版本升级时,对比其它操作系统,兼容性都要做得好,不需要用户费神DIY处理一些BUG。64位windows上市后大多以前32位的程序依旧正常地运行,当然这里主要指用户态程序。那64位windows是如何支持32位程序运行的呢?之前在看《windows核心编程》一书时只知道这个机制的名字叫wow64,但是具体如何实现的一无所知。为此我上网查阅资料,结果相关文章都讲得很笼统,包括Microsoft官方文档也是从很上层架构上进行了介绍,对于搞逆向的人来说,只了解架构不看代码怎么能忍,windows就在手边,何不亲自研究窥探一把庐山面目呢?说搞就搞,从代码的角度看一下这个wow64的大概。这里插一句,其实在着手了解wow64机制前,是另外一个问题先引起了我的好奇:64位CPU比32位CPU除了每个寄存器宽度多了32bit,还多了几个通用寄存器:R8, R9, R10, R11, R12, R13, R14, R15,那32位程序在win64上运行时这些新加的寄存器就没用了吗?这个问题最后也会得到解决。首先,先从宏观分析一下,32位程序的运行需要软硬件两个大方面的支持:1)硬件上,CPU的解码模式需要是32位模式。64位CPU(我只熟悉INTEL的)是通过GDT表中CS段所对应的表项中L标志位来确定当前解码模式的。这里不展开描述GDT表与CPU运行模式的关系,感兴趣的可以参看 http://www.secbox.cn/hacker/program/9875.html2)软件上,操作系统需要提供32位的用户态运行时环境(C库,WINDOWS API)对32位程序支持,其次因为win64内核是64位模式的,所以32位运行时环境在与64位内核交互时需要有状态转换。当然另外肯定还有大量其它的兼容32位软件所需要实现的功能,比如资源管理,句柄管理,结构化错误管理等等,这些属于细节就不进行研究了,我这里先看一个大体。好了,接下来针对上面的分析进行探索。关于32位运行时环境这点,可以在c:/windows/syswow64中发现许多和c:/windows/system32下同名的动态链接库,如kernel32.dll, ntdll.dll, msvcrt.dll, ws2_32.dll等,其实这些都是32位的版本。像wow64名字所传达的含义一样,syswow64文件夹下的这些库相当于在64位windows中构建了一个32位windows子系统环境,我们32位的程序能正常在win64上运行正是靠这个子环境负责与64位环境进行了交互和兼容,所以需要重点探究下这个32位子环境是如何与win64环境交互的。我这里用到的工具是 PCHunter 与调试器 MDebug,静态分析工具 IDA。了解 windows 的读者都知道 ntdll.dll 是用户态与内核态交互的桥梁,所以我选择从 ntdll.dll 入手,选择了逻辑简单的 NtAllocateVirtualMemory 函数。首先看一下原生32位操作系统里这个函数是什么样的。我手头有个 win8 32bit 版本,利用 MDebug 直接转到 NtAllocateVirtualMemory 函数查看反汇编,可以看到,在设置好调用号 0x19B 之后直接就使用 sysenter 进行了系统调用,中间没有其它操作,下面是相应的反汇编代码:NtAllocateVirtualMemory: 7778F048 mov eax, 0x19B 7778F04D call sub_7778F055(7778F055) 7778F052 ret 0x18 sub_7778F055: 7778F055 mov edx, esp 7778F057 sysenter 7778F059 ret看完原生32位操作系统里的样子,win64 中运行一个 32 位程序时它的进程空间里的NtAllocateVirtualMemory 是一番什么情景呢?我手头有 win7 64bit 版,运行的一个32bit程序进行调试,可以看到 NtAllocateVirtualMemory 的形式如下:NtAllocateVirtualMemory: 77C8FAD0 mov eax,0x15 77C8FAD5 xor ecx,ecx 77C8FAD7 lea edx,[esp+0x4] 77C8FADB call dword ptr fs:[000000C0] 77C8FAE2 add esp,4 77C8FAE5 ret 0x18OK,区别很明显,wow64中的 ntdll.dll 与原生32位 windows 中的 ntdll.dll 有了变动,它不再是与内核交互的最后一个用户态模块,而是call 进了fs:[C0]处的函数,隐约感觉这里就是打开wow64秘密的入口。fs:[C0] 是什么呢?Windows操作系统中,fs寄存器用于记录线程环境块TEB,根据TEB结构体定义可以看出0xC0偏移处的定义为:PVOID WOW32Reserved; // 0C0其实在wow64之前还有wow32机制,用于兼容16位程序在32位windows上运行,与wow64异曲同工。所以 windows 系统在 wow64 中直接也拿这个保留位置用于进行32位64位环境切换的跳板。单步跟进,发现fs:[C0]处只有一行代码:752B2320 jmp 0033:752B271E这里是一个长跳转,目的地址是内存752B271E处,但是MDebug调试器显示752B271E处于未知模块。这时需要借助PCHunter,通过PcHunter发现该地址其实位于一个叫wow64cpu.dll的模块中,值得注意的一点是,该模块来自 system32 而非syswow64 目录,是64位的文件模块,也就是说,wow64下32位程序的进程空间内同时加载了32位与64位的可执行文件模块!在这个32位程序的进程空间里一共有4个来自SYSTEM32 目录64位的“客人”:终于,这里有了真正的64位 ntdll.dll 的出现。所以很容易可以推断,wow64.dll, wow64win.dll, wow64cpu.dll 组成了环境转换模块,而最终依然是ntdll.dll 负责与内核交互,wow64中这4个模块在默默地在后台支持着32位程序的运行。上面说到这里经历了一个长跳转,段寄存器由0x23变换为0x33,在win64中,0x23和0x33所对应的GDT表项中CPU的模式分别为32位与64位。自此,CPU解码模式由32位切换为64位。当然,故事还没结束。不过由于调试器是32位,无法准确捕获接下来发生的事情,单步跟进也没用了,我们转为使用IDA静态分析。找到 752B271E 所对应的 wow64cpu.dll 中的位置:00000000752B271E mov r8d,[esp] //取出返回地址 00000000752B2723 mov [r13+0xBC],r8d //保存返回地址 00000000752B272A mov [r13+0xC8],esp //保存32位环境堆栈指针 00000000752B2731 mov rsp,[r12+0x1480] //切换至64位环境堆栈 00000000752B2739 and qword ptr [r12+0x1480],0x0 00000000752B2742 mov r11d,edx 00000000752B2745 jmp qword ptr [r15+rcx*8]第一句读取[esp]的值其实是把返回地址取出,接着保存到了r13所指向的地方,同时还保存了esp,然后重新赋值了rsp。看了这一小段,我们基本可以猜测到,在wow64中那个幕后的64位环境里其实是有自己的堆栈和执行上下文的,在CPU由32位切换到64位后,堆栈也相应切换。好了,下面要搞最后一句跳向了哪里,也就是[r15+rcx*8]的值,我们上面考察的 NtAllocateVirtualMemory 有 xor ecx, ecx 的操作,所以到这里时rcx = 0,所以就我们考察的例子而言,最后就是跳转到了[r15]。那,r15的值是多少?这是有点棘手的问题。Wow64中32位程序只能由32位调试器调试,但是32位调试器下又无法获得64位模式下才可见的r15的值,怎么办?我这里使用shellcode的方式,利用32位MDebug调试shellcode的功能调试精心准备的一段shellcode,这段shellcode的作用独特而简单:让CPU切换到64位模式下“潇洒走一回”,将R8 ~R15的值记录到堆栈中,接着切换回32位模式。shellcode的二进制为:\x6A\x33\xE8\x00\x00\x00\x00\x83\x04\x24\x05\xCB\x48\xB8\x88\x77\x66\x55\x44\x33\x22\x11\x50\x41\x50\x41\x51\x41\x52\x41\x53\x41\x54\x41\x55\x41\x56\x41\x57\x50\xE8\x00\x00\x00\x00\xC7\x44\x24\x04\x23\x00\x00\x00\x83\x04\x24\x0D\xCB它的反汇编如下:/*开始时CPU处于32位模式*/ Push 0x33 // cs = 0x33 Call L1 L1: add [esp], 5 retf // far ret,切换CPU状态 /*此时CPU处于64位模式*/ mov rax, 1122334455667788h //将r8~r15用特殊值与周边数据隔开,方便查看 push rax push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 push rax Call L2: L2: mov [esp + 4], 0x23 // cs = 0x23 add [esp], 0xd retf虽然32位调试器无法对64位代码运行时下断,但是可以在切换回32位模式后的地方下断点。所以在这段代码后下一个断,运行代码。执行完毕后,查看一下堆栈上的收获: 地址 内容 0018FEA0 1122334455667788 0018FEA8 00000000752B2450 r15 0018FEB0 000000000008EC80 r14 0018FEB8 000000000008FD20 r13 0018FEC0 000000007EFDB000 r12 0018FEC8 0000000000000246 r11 0018FED0 0000000000000000 r10 0018FED8 0000000077C8FAFA r9 0018FEE0 000000000000002B r8 0018FEE8 1122334455667788 Bingo!我们成功获得到了32位程序运行环境下R8~R15的值,根据R15的值定位出它同样位于wow64cpu.dll文件模块内,根据R15的值 找到wow64cpu.dll中相应的位置,发现是指向了一堆函数指针:.text:0000000078B62450 dq offset TurboDispatchJumpAddressEnd .text:0000000078B62458 dq offset sub_78B62DBA .text:0000000078B62460 dq offset sub_78B62BCE .text:0000000078B62468 dq offset sub_78B62D6A //后面还有很多函数指针,此处省略其实在第一次打开wow64cpu.dll寻找752B271E位置时,就可以看到它附近有一个名为CpuSimulate的函数,里面有这样的操作:.text:0000000078B625F9 mov r12, gs:30h .text:0000000078B62602 lea r15, off_78B62450可以看到r15是指向了偏移78B62450处,对应动态加载后就是752B2450。所以这也印证了我们的实验结果。另外还可以看到的一点是r12指向了64位下的TEB(64位下gs段寄存器用于记录TEB结构)。所以很显然,[r15]是指向了TurboDispatchJumpAddressEnd处,就是上文jmp qword ptr [r15+rcx*8]所要跳转到的地方(因为ecx = 0),看一下它的代码:TurboDispatchJumpAddressEnd: .text:0000000078B62749 mov [r13+0A4h], esi .text:0000000078B62750 mov [r13+0A0h], edi .text:0000000078B62757 mov [r13+0A8h], ebx .text:0000000078B6275E mov [r13+0B8h], ebp //保存32位环境下的寄存器 .text:0000000078B62765 pushfq .text:0000000078B62766 pop rbx .text:0000000078B62767 mov [r13+0C4h], ebx //保存32位环境的eflags .text:0000000078B6276E mov ecx, eax //调用号 .text:0000000078B62770 call cs:Wow64SystemServiceEx //继续完成未尽竟的事业 .text:0000000078B62776 mov [r13+0B4h], eax .text:0000000078B6277D jmp loc_78B62611上面的代码最后跳转到78B62611,loc_78B62611的代码如下:text:0000000078B62611 loc_78B62611: .text:0000000078B62611 and dword ptr [r13+2D0h], 1 .text:0000000078B62619 jz loc_78B626CE .text:0000000078B6261F movaps xmm0, xmmword ptr [r13+170h] .text:0000000078B62627 movaps xmm1, xmmword ptr [r13+180h] .text:0000000078B6262F movaps xmm2, xmmword ptr [r13+190h] .text:0000000078B62637 movaps xmm3, xmmword ptr [r13+1A0h] .text:0000000078B6263F movaps xmm4, xmmword ptr [r13+1B0h] .text:0000000078B62647 movaps xmm5, xmmword ptr [r13+1C0h] .text:0000000078B6264F mov ecx, [r13+0B0h] .text:0000000078B62656 mov edx, [r13+0ACh] .text:0000000078B6265D and dword ptr [r13+2D0h], 0FFFFFFFEh .text:0000000078B62665 mov edi, [r13+0A0h] .text:0000000078B6266C mov esi, [r13+0A4h] .text:0000000078B62673 mov ebx, [r13+0A8h] .text:0000000078B6267A mov ebp, [r13+0B8h] .text:0000000078B62681 mov eax, [r13+0B4h] //恢复32位环境寄存器 .text:0000000078B62688 mov [r12+1480h], rsp //保存64位环境堆栈指针 .text:0000000078B62690 mov [rsp+0B8h+var_B0], 23h .text:0000000078B62697 mov [rsp+0B8h+var_98], 2Bh .text:0000000078B6269E mov r8d, [r13+0C4h] //之前保存的32位环境eflags .text:0000000078B626A5 and dword ptr [r13+0C4h], 0FFFFFEFFh .text:0000000078B626B0 mov [rsp+0B8h+var_A8], r8d .text:0000000078B626B5 mov r8d, [r13+0C8h] .text:0000000078B626BC mov [rsp+0B8h+var_A0], r8 .text:0000000078B626C1 mov r8d, [r13+0BCh] .text:0000000078B626C8 mov [rsp+0B8h+var_B8], r8 .text:0000000078B626CC iretq //排好堆栈,返回至32位模式返回地址处可以看到,在 TurboDispatchJumpAddressEnd 代码片段中,调用了一个外部函Wow64SystemServiceEx,由这个函数再继续把下面的事情做完,最终调用64位的 ntdll.dll的 NtAllocateVirtualMemory 来完成整个操作。TurboDispatchJumpAddressEnd 最后跳转至78B62611,将CPU主要寄存器值恢复至之前保存好的32位环境中的值,同时在堆栈中排布好返回地址,cs段寄存器值,eflag值,执行iretq,返回至32位环境中,在我们的例子中,即返回到 NtAllocateVirtualMemory 中 call  dword ptr fs:[C0] 的下一句,看起来像真的执行了一个普通函数一样。上面讲到跳转的函数指针表是根据r15+rcx*8来得到的,在32位进程空间的那个ntdll.dll里面 call  dword ptr fs:[C0] 前都有对ecx的赋值,我们可以推测在wow64中,系统调用被分成多类,类别号存在于rcx中,根据rcx的值来进行不同类别的模拟转换。Wow64SystemServiceEx 做的事情就暂时不详细研究了,感兴趣的可以细细钻研。对这次简单的wow64之旅做个小总结:1) windows/syswow64目录下的大量DLL库与SYSTEM32目录下的wow64.dll, wow64cpu.dll, wow64win.dll, ntdll.dll 支撑着wow64机制。2) Wow64下32位进程中实际有32位和64位两个逻辑子空间,每个子空间都 有各自的数据结构、堆栈,64位子空间负责与操作系统内核交互:32位用户态模式  <--------->  64位用户态模式  <------------------> 64位内核3)Wow64模式下,那些不可见的寄存器并不都是闲置不用的,在切换到64位环境后全部启用,和正常64位程序无差别。且经过分析可以知道有确切作用的寄存器有:R12: 指向64位环境的TEB结构体 R13:指向保存32位环境CPU的状态的位置R15: 指向跳转函数指针列表的起始上面是针对win7下做的一个wow64机制小探索,我也简单看了下在win8和win10下的wow64过程,在反汇编代码上有些小不同,但是逻辑原理是完全相同的,感兴趣的读者可以搞一把。
4 0 752天前
admin
1859
原文转载自:https://www.zhihu.com/question/27971703   作者:pezy根据 Appending Binary Files Using the COPY Command 可粗略的认为,就是以二进制的方式合并两个文件到一个新文件中。举例说明:echo Hello > 1.txt echo World > 2.txt copy /b 1.txt+2.txt 3.txt 那么此刻 3.txt 中应该是Hello World 如果仅仅实现上述例子中的基本功能,使用几个系统的 API 就可以搞定。代码如下:#include <windows.h> #include <stdio.h> void main() { HANDLE hFile; HANDLE hAppend; DWORD dwBytesRead, dwBytesWritten, dwPos; BYTE buff[4096]; // Copy the existing file. BOOL bCopy = CopyFile(TEXT("1.txt"), TEXT("3.txt"), TRUE); if (!bCopy) { printf("Could not copy 1.txt to 3.txt."); return; } // Open the existing file. hFile = CreateFile(TEXT("2.txt"), // open 2.txt GENERIC_READ, // open for reading 0, // do not share NULL, // no security OPEN_EXISTING, // existing file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { printf("Could not open 2.txt."); return; } // Open the existing file, or if the file does not exist, // create a new file. hAppend = CreateFile(TEXT("3.txt"), // open 3.txt FILE_APPEND_DATA, // open for writing FILE_SHARE_READ, // allow multiple readers NULL, // no security OPEN_ALWAYS, // open or create FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (hAppend == INVALID_HANDLE_VALUE) { printf("Could not open 3.txt."); return; } // Append the first file to the end of the second file. // Lock the second file to prevent another process from // accessing it while writing to it. Unlock the // file when writing is complete. while (ReadFile(hFile, buff, sizeof(buff), &dwBytesRead, NULL) && dwBytesRead > 0) { dwPos = SetFilePointer(hAppend, 0, NULL, FILE_END); LockFile(hAppend, dwPos, 0, dwBytesRead, 0); WriteFile(hAppend, buff, dwBytesRead, &dwBytesWritten, NULL); UnlockFile(hAppend, dwPos, 0, dwBytesRead, 0); } // Close both files. CloseHandle(hFile); CloseHandle(hAppend); } 将代码中的 1.txt, 2.txt, 3.txt 改为任何别的文件,是一样的。如题主补充的要求,做如下替换即可:1.txt -> a.jpg2.txt -> b.txt3.txt -> c.txt (文本),c.jpg(更改后缀,成为图片)诸如 jpg 之类的格式,依然是二进制文件,经过渲染,表现为图片而已。
5 0 791天前
快速发帖 高级模式
桂公网安备 45010302000666号 桂ICP备14001770-3号
感谢景安网络提供数据空间
本站CDN由七牛云知道创宇提供支持
免责声明: 本网不承担任何由内容提供商提供的信息所引起的争议和法律责任。
Your IP: 3.85.245.126 , 2019-10-24 00:08:14 , Processed in 2.20312 second(s).
Powered by HadSky 7.3.4