今天開始去上第一節的小提琴課
滿懷期待的去,有點小小失落的回家
令人失望的是小提琴老師的素質好像有點低落
應該沒錯啦,依照我聽他拉的水準,應該也學沒兩年
上課也是叫我們練習拉琴,不是主要放在教技巧
(一拍拉一下半弓,兩拍拉兩下半弓,四拍拉四下半弓,八拍拉八下1/4弓)
我覺得應該在一小時半的課中教多些內容,然後再讓我們回家練習的說
或是看我們在練習拉琴時矯正我們的姿勢,但是
好像都沒有.......
唉,錢都繳了,現在只能希望是我肉腳,聽不出老師的水準吧
真該聽同事的話去請家教的

eager 發表在 痞客邦 留言(0) 人氣()

今天開始去上第一節的小提琴課
滿懷期待的去,有點小小失落的回家
令人失望的是小提琴老師的素質好像有點低落
應該沒錯啦,依照我聽他拉的水準,應該也學沒兩年
上課也是叫我們練習拉琴,不是主要放在教技巧
(一拍拉一下半弓,兩拍拉兩下半弓,四拍拉四下半弓,八拍拉八下1/4弓)
我覺得應該在一小時半的課中教多些內容,然後再讓我們回家練習的說
或是看我們在練習拉琴時矯正我們的姿勢,但是
好像都沒有.......
唉,錢都繳了,現在只能希望是我肉腳,聽不出老師的水準吧
真該聽同事的話去請家教的

eager 發表在 痞客邦 留言(0) 人氣()

唉,最近好不容易想要用低階socket作一些網路偵測功能
拿了一些code來參考,寫了一堆,結果都不能用
花了一整天時間,才查到原因.............
原來win2k sp2版本後,因為安全需求,把raw socket的TCP封包與source IP不是本機IP的UDP封包
都禁止使用了
阿,還是用libpacp吧,殘念
================================網路上的討論
Asunto: Re: sendto() 10004 error
De: arkadyf@hotmailxdotx.com (Arkady Frenkel)
Foro: microsoft.public.platformsdk.networking
Organización: Texas Instruments
Fecha: 24. Aug 2004, 09:41:48
Referencia: 1 2 3
Thanks for URL , Alun ! That shows that protection against dos attacks much
more sophisticated that I thought before :)
Arkady
"Alun Jones [MSFT]" <alunj@online.microsoft.com> wrote in message
news:%23ASKt2UiEHA.1384@TK2MSFTNGP10.phx.gbl...
> Specifically, raw TCP sends are forbidden. Raw UDP sends that forge the
> source address are also forbidden. Other raw socket sends work just fine.
>
> For details, see
>
<URL:http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/sp2netwk
> .mspx#XSLTsection127121120120>
>
> Alun.
> ~~~~
>
> "Arkady Frenkel" <arkadyf@hotmailxdotxcom> wrote in message
> news:eX3HKd7hEHA.2604@TK2MSFTNGP09.phx.gbl...
> > Raw socket send operation forbidden in SP2 , that part of struggle with
> > DOS ( deny of service ) attacks
> > Arkady
> >
> > "R-e-D" <red@redkod.org> wrote in message
> > news:XnF954C8560D604Dredredkodorg@212.27.42.66...
> > > Hello,
> > >
> > > When I call sendto() in order to send my packet this error appears:
> > >
> > > "Une opération de blocage a été interrompue par un appel
> > > à WSACancelBlockingCall", Code 10004
> > >
> > > This problem is present since the installation of the Service Pack 2
> > > of Windows XP.
> > >
> > > Code:
> > > SOCKET sock;
> > > ....
> > > sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, NULL, 0,
> > > WSA_FLAG_OVERLAPPED); ....
> > > setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *) &optval,
> > > sizeof(optval)); ....
> > > bytes_sent = sendto(sock, packet, len, 0, to, sizeof(struct
> > > sockaddr_in)); if (bytes_sent == SOCKET_ERROR || bytes_sent != len)
> > > ....
> > > Error !
> > >
> > >
> > > Would somebody have a solution ?
> > > Sorry for my english.
> > >

eager 發表在 痞客邦 留言(0) 人氣()


唉,最近好不容易想要用低階socket作一些網路偵測功能
拿了一些code來參考,寫了一堆,結果都不能用
花了一整天時間,才查到原因.............
原來win2k sp2版本後,因為安全需求,把raw socket的TCP封包與source IP不是本機IP的UDP封包
都禁止使用了
阿,還是用libpacp吧,殘念
================================網路上的討論
Asunto: Re: sendto() 10004 error
De: arkadyf@hotmailxdotx.com (Arkady Frenkel)
Foro: microsoft.public.platformsdk.networking
Organización: Texas Instruments
Fecha: 24. Aug 2004, 09:41:48
Referencia: 1 2 3
Thanks for URL , Alun ! That shows that protection against dos attacks much
more sophisticated that I thought before :)
Arkady
"Alun Jones [MSFT]" wrote in message
news:%23ASKt2UiEHA.1384@TK2MSFTNGP10.phx.gbl...
> Specifically, raw TCP sends are forbidden. Raw UDP sends that forge the
> source address are also forbidden. Other raw socket sends work just fine.
>
> For details, see
>

> .mspx#XSLTsection127121120120>
>
> Alun.
> ~~~~
>
> "Arkady Frenkel" wrote in message
> news:eX3HKd7hEHA.2604@TK2MSFTNGP09.phx.gbl...
> > Raw socket send operation forbidden in SP2 , that part of struggle with
> > DOS ( deny of service ) attacks
> > Arkady
> >
> > "R-e-D" wrote in message
> > news:XnF954C8560D604Dredredkodorg@212.27.42.66...
> > > Hello,
> > >
> > > When I call sendto() in order to send my packet this error appears:
> > >
> > > "Une opération de blocage a été interrompue par un appel
> > > à WSACancelBlockingCall", Code 10004
> > >
> > > This problem is present since the installation of the Service Pack 2
> > > of Windows XP.
> > >
> > > Code:
> > > SOCKET sock;
> > > ....
> > > sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, NULL, 0,
> > > WSA_FLAG_OVERLAPPED); ....
> > > setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *) &optval,
> > > sizeof(optval)); ....
> > > bytes_sent = sendto(sock, packet, len, 0, to, sizeof(struct
> > > sockaddr_in)); if (bytes_sent == SOCKET_ERROR || bytes_sent != len)
> > > ....
> > > Error !
> > >
> > >
> > > Would somebody have a solution ?
> > > Sorry for my english.
> > >

eager 發表在 痞客邦 留言(3) 人氣()

Scan,是一切入侵的基礎,掃描探測一台主機包括是為了確定主機是否活動、主機系統、正在使用哪些端口、提供了哪些服務、相關服務的軟體版本等等,對這些內容的探測就是為了"對症下藥"。對主機的探測工具非常多,比如大名鼎鼎的nmap、netcat、superscan,以及國內的X-Scanner等等。
ICMP協議──PING是最常用的,也是最簡單的探測手段,用來判斷目標是否活動。實際上Ping是向目標發送一個要求回顯(Type = 8)的ICMP數據報,當主機得到請求后,再返回一個回顯(Type = 0)數據報。而且Ping 程式一般是直接實現下系統內核中的,而不是一個用戶進程。Ping是最基本的探測手段,Ping Sweep(Ping掃射)就是對一個網段進行大範圍的Ping,由此確定這個網段的網路運作情況,比如著名的fping工具就是進行Ping掃射的。
不過現下連基本的個人防火牆都對Ping做了限制,這個也太基本了。如果透過防火牆,如何獲得最理想的目標圖,也是很多人整天思考的問題。我們這裡介紹的一些掃描技術就是要儘可能地繞過一些安全防護設備,並且盡量保護自己,同時達到我們需要的目的。
  一、高級ICMP掃描技術
  Ping就是利用ICMP協議走的,高級的ICMP掃描技術主要是利用ICMP協議最基本的用途︰報錯。根據網路協議,如果按照協議出現了錯誤,那么接收端將產生一個ICMP的錯誤報文。這些錯誤報文並不是主動發送的,而是由於錯誤,根據協議自動產生。
  當IP數據報出現checksum和版本的錯誤的時候,目標主機將拋棄這個數據報,如果是checksum出現錯誤,那么路由器就直接丟棄這個數據報了。有些主機比如AIX、HP-UX等,是不會發送ICMP的Unreachable數據報的。
  我們利用下面這些特性︰
  1、向目標主機發送一個只有IP頭的IP數據包,目標將返回Destination Unreachable的ICMP錯誤報文。
  2、向目標主機發送一個壞IP數據報,比如,不正確的IP頭長度,目標主機將返回Parameter Problem的ICMP錯誤報文。
  3、當數據包分片但是,卻沒有給接收端足夠的分片,接收端分片組裝超時會發送分片組裝超時的ICMP數據報。
  向目標主機發送一個IP數據報,但是協議項是錯誤的,比如協議項不可用,那么目標將返回Destination Unreachable的ICMP報文,但是如果是在目標主機前有一個防火牆或者一個其他的過濾裝置,可能過濾掉提出的要求,從而接收不到任何回應。可以使用一個非常大的協議數字來作為IP頭部的協議內容,而且這個協議數字至少在今天還沒有被使用,應該主機一定會返回Unreachable,如果沒有Unreachable的ICMP數據報返回錯誤提示,那么就說明被防火牆或者其他設備過濾了,我們也可以用這個辦法來探測是否有防火牆或者其他過濾設備存在。
  利用IP的協議項來探測主機正在使用哪些協議,我們可以把IP頭的協議項改變,因為是8位的,有256種可能。透過目標返回的ICMP錯誤報文,來作判斷哪些協議在使用。如果返回Destination Unreachable,那么主機是沒有使用這個協議的,相反,如果什麼都沒有返回的話,主機可能使用這個協議,但是也可能是防火牆等過濾掉了。NMAP的IP Protocol scan也就是利用這個原理。
  利用IP分片造成組裝超時ICMP錯誤消息,同樣可以來達到我們的探測目的。當主機接收到丟失分片的數據報,並且在一定時間內沒有接收到丟失的數據報,就會丟棄整個包,並且發送ICMP分片組裝超時錯誤給原發送端。我們可以利用這個特性製造分片的數據包,然後等待ICMP組裝超時錯誤消息。可以對UDP分片,也可以對TCP甚至ICMP數據包進行分片,只要不讓目標主機獲得完整的數據包就行了,當然,對于UDP這種非連接的不可靠協議來說,如果我們沒有接收到超時錯誤的ICMP返回報,也有可能時由於線路或者其他問題在傳輸過程中丟失了。
  我們能夠利用上面這些特性來得到防火牆的ACL(access list),甚至用這些特性來獲得整個網路拓撲架構。如果我們不能從目標得到Unreachable報文或者分片組裝超時錯誤報文,可以作下面的判斷︰
  1、防火牆過濾了我們發送的協議類型
  2、防火牆過濾了我們指定的端口
  3、防火牆阻塞ICMP的Destination Unreachable或者Protocol Unreachable錯誤消息。
  4、防火牆對我們指定的主機進行了ICMP錯誤報文的阻塞。
  二、高級TCP掃描技術
  最基本的利用TCP掃描就是使用connect(),這個很容易實現,如果目標主機能夠connect,就說明一個相應的端口打開。不過,這也是最原始和最先被防護工具拒絕的一種。
  在高級的TCP掃描技術中主要利用TCP連接的三次握手特性和TCP數據頭中的標誌位來進行,也就是所謂的半開掃描。
  先認識一下TCP數據報頭的這六個標誌位。
  URG︰(Urgent Pointer field significant)緊急指針。用到的時候值為1,用來處理避免TCP數據流中斷
  ACK︰(Acknowledgment field significant)置1時表示確認號(Acknowledgment Number)為合法,為0的時候表示數據段不包含確認訊息,確認號被忽略。
  PSH︰(Push Function),PUSH標誌的數據,置1時請求的數據段在接收方得到后就可直接送到應用程式,而不必等到緩沖區滿時才傳送。
  RST︰(Reset the connection)用于複位因某種原因引起出現的錯誤連接,也用來拒絕非法數據和請求。如果接收到RST位時候,通常發生了某些錯誤。
  SYN︰(Synchronize sequence numbers)用來建立連接,在連接請求中,SYN=1,ACK=0,連接附應時, SYN=1,ACK=1。即,SYN和ACK來區分Connection Request和Connection Accepted。
  FIN︰(No more data from sender)用來釋放連接,表明發送方已經沒有數據發送了。
  TCP協議連接的三次握手過程是這樣的︰
  首先客戶端(請求方)在連接請求中,發送SYN=1,ACK=0的TCP數據包給伺服器端(接收請求端),表示要求同伺服器端建立一個連接;然後如果伺服器端附應這個連接,就返回一個SYN=1,ACK=1的數據報給客戶端,表示伺服器端同意這個連接,並要求客戶端確認;最後客戶端就再發送SYN=0,ACK=1的數據包給伺服器端,表示確認建立連接。
  我們就利用這些標誌位和TCP協議連接的三次握手特性來進行掃描探測。
  SYN 掃描
  這種掃描模式也被稱為"半打開" 掃描,因為利用了TCP協議連接的第一步,並且沒有建立一個完整的TCP連接。實現辦法是向遠端主機某端口發送一個只有SYN標誌位的TCP數據報,如果主機回饋一個SYN || ACK數據包,那么,這個主機正在監聽該端口,如果回饋的是RST數據包,說明,主機沒有監聽該端口。在X-Scanner 上就有SYN的選擇項。
  ACK 掃描
  發送一個只有ACK標誌的TCP數據報給主機,如果主機回饋一個TCP RST數據報來,那么這個主機是存在的。也可以透過這種技術來確定對方防火牆是否是簡單的分組過濾,還是一個基于狀態的防火牆。
  FIN
  對某端口發送一個TCP FIN數據報給遠端主機。如果主機沒有任何回饋,那么這個主機是存在的,而且正在監聽這個端口;主機回饋一個TCP RST回來,那么說明該主機是存在的,但是沒有監聽這個端口。
  NULL
  即發送一個沒有任何標誌位的TCP包,根據RFC793,如果目標主機的相應端口是關閉的話,應該發送回一個RST數據包。
  FIN+URG+PUSH
  向目標主機發送一個Fin、URG和PUSH分組,根據RFC793,如果目標主機的相應端口是關閉的,那么應該返回一個RST標誌。
  上面這些辦法可以繞過一些防火牆,從而得到防火牆后面的主機訊息,當然,是在不被欺騙的情況下的。這些方法還有一個好處就是比較難于被記錄,有的辦法即使在用netstat命令上也根本顯示不出來,而且一般的安全防護設備也根本不記錄這些內容,這樣能夠更好地隱藏自己。
三、高級UDP掃描技術
  在UDP實現的掃描中,多是了利用和ICMP進行的組合進行,這在ICMP中以及提及了。還有一些特殊的就是UDP回饋,比如SQL SERVER,對其1434端口發送‘x02'或者‘x03'就能夠探測得到其連接端口。
  下面這段程式就是一個TCP探測的例子,當然,並沒有做得完美,因為沒有接收部分,而在WIN2000下實際就是一個選擇性的SNIFFER,呵呵,大家可以使用其他的SNIFFER來實現同樣的目的。也可以改變下面的程式只發送IP包,利用ICMP特性來實現探測。
#include 〈stdio.h>;
#include 〈winsock2.h>;
#include 〈ws2tcpip.h>;
#define SOURCE_PORT 7234
#define MAX_RECEIVEBYTE 255
typedef struct ip_hdr //定義IP首部
{
unsigned char h_verlen; //4位首部長度,4位IP版本號
unsigned char tos; //8位服務類型TOS
unsigned short total_len; //16位總長度(位元組)
unsigned short ident; //16位標識
unsigned short frag_and_flags; //3位標誌位
unsigned char ttl; //8位生存時間 TTL
unsigned char proto; //8位協議 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校驗和
unsigned int sourceIP; //32位源IP位址
unsigned int destIP; //32位目的IP位址
}IPHEADER;
typedef struct tsd_hdr //定義TCP偽首部
{
unsigned long saddr; //源位址
unsigned long daddr; //到達站址
char mbz;
char ptcl; //協議類型
unsigned short tcpl; //TCP長度
}PSDHEADER;
typedef struct tcp_hdr //定義TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列號
unsigned int th_ack; //32位確認號
unsigned char th_lenres; //4位首部長度/6位保留字
unsigned char th_flag; //6位標誌位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校驗和
USHORT th_urp; //16位緊急數據偏移量
}TCPHEADER;
//CheckSum:計算校驗和的子函數
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >;1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >;>; 16) + (cksum &; 0xffff);
cksum += (cksum >;>;16);
return (USHORT)(~cksum);
}
void usage()
{
printf(";****************************************** ";);
printf(";TCPPing ";);
printf("; Written by Refdom ";);
printf("; Email: refdom@263.net ";);
printf(";Useage: TCPPing.exe Target_ip Target_port ";);
printf(";******************************************* ";);
}
int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;
char szSendBuf[60]={0};
BOOL flag;
int rect,nTimeOver;
usage();
if (argc!= 3)
{ return false; }
if (WSAStartup(MAKEWORD(2,2), &;WSAData)!=0)
{
printf(";WSAStartup Error! ";);
return false;
}
if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
printf(";Socket Setup Error! ";);
return false;
}
flag=true;
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&;flag,sizeof(flag))==SOCKET_ERROR)
{
printf(";setsockopt IP_HDRINCL error! ";);
return false;
}
nTimeOver=1000;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&;nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)
{
printf(";setsockopt SO_SNDTIMEO error! ";);
return false;
}
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(atoi(argv[2]));
addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);
//
//
//填充IP首部
ipHeader.h_verlen=(4〈〈4 | sizeof(ipHeader)/sizeof(unsigned long));
// ipHeader.tos=0;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
ipHeader.ident=1;
ipHeader.frag_and_flags=0;
ipHeader.ttl=128;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.sourceIP=inet_addr(";本地位址";);
ipHeader.destIP=inet_addr(argv[1]);
//填充TCP首部
tcpHeader.th_dport=htons(atoi(argv[2]));
tcpHeader.th_sport=htons(SOURCE_PORT); //源端口號
tcpHeader.th_seq=htonl(0x12345678);
tcpHeader.th_ack=0;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4〈〈4|0);
tcpHeader.th_flag=2; //修改這裡來實現不同的標誌位探測,2是SYN,1是FIN,16是ACK探測 等等
tcpHeader.th_win=htons(512);
tcpHeader.th_urp=0;
tcpHeader.th_sum=0;
psdHeader.saddr=ipHeader.sourceIP;
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));
//計算校驗和
memcpy(szSendBuf, &;psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &;tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &;ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &;tcpHeader, sizeof(tcpHeader));
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &;ipHeader, sizeof(ipHeader));
rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),
0, (struct sockaddr*)&;addr_in, sizeof(addr_in));
if (rect==SOCKET_ERROR)
{
printf(";send error!:%d ";,WSAGetLastError());
return false;
}
else
printf(";send ok! ";);
closesocket(sock);
WSACleanup();
return 0;
}

eager 發表在 痞客邦 留言(0) 人氣()

作者Blog︰http://blog.csdn.net/EA/
=======================================
1、MFC框架
  (DX8MFC)
  這裡的MFC框架指的是一個符合遊戲開發應用的框架,當然你也可以寫一個符合你要求的MFC框架。如果你對MF
C比較熟悉的話可以直接從第二章開始閱讀。本框架是以後幾個例子的基礎,如果你對MFC不是很了解的話,就要認
真閱讀本章,以求對這個MFC框架有一個深入的了解。
  框架中包括兩個類︰
  CDX8MFCApp類和CFrameWin類,CDX8MFCApp類是應用程式類,CFrameWin類是框架的主類,以後我們的大部分代
碼都是從這裡擴展的。首先來看一看CDX8MFCApp類,它包括CDX8MFCApp()、ExitInstance()、InitInstance()、On
Idle(LONG lCount)等成員函數和一個Game對象。
  InitInstance()成員函數在程式初始化時就被調用,在這裡我建立了一個窗口︰
  ExitInstance()成員函數在程式終止時被調用,在這裡我們釋放一些對象和指針︰
  OnIdle(LONG lCount)成員函數會在沒有Windows消息要處理的時候被調用,也就是說OnIdle()成員函數會不斷
的被調用,這正好被我們用作遊戲循環。
  BOOL CDX8MFCApp::InitInstance()
  {
   // The one and only window has been initialized, so show and update it.
   m_pMainWnd = new CFrameWin();
   m_pMainWnd->ShowWindow(m_nCmdShow);
   m_pMainWnd->UpdateWindow();
   Game = (CFrameWin*) m_pMainWnd;
   Game->Init();
   return TRUE;
  }
  ExitInstance()成員函數在程式終止時被調用,在這裡我們釋放一些對象和指針︰
  int CDX8MFCApp::ExitInstance()
  {
   // TODO: Add your specialized code here and/or call the base class
   Game->End();
   delete Game;
   return CWinApp::ExitInstance();
  }
  OnIdle(LONG lCount)成員函數會在沒有Windows消息要處理的時候被調用,也就是說OnIdle()成員函數會不斷
的被調用,這正好被我們用作遊戲循環。
  BOOL CDX8MFCApp::OnIdle(LONG lCount)
  {
   // TODO: Add your specialized code here and/or call the base class
   if(Game->window_active==TRUE)
    {
     Game->Active();
     Game->window_active=FALSE;
    }
   Game->Go();
   return TRUE;
  }
  Game對象是一個CFrameWin類指針,我們在InitInstance()成員函數中創建了一個CFrameWin對象並把CFrameWi
n對象的指針值賦給Game。下面我們來看一看CFrameWin類, 它包括Active()、End()、Go()、Init()、Update()等
成員函數。
  Init()成員函數,你可以在這裡做一些自己的初始化。回顧CDX8MFCApp類的InitInstance()成員函數可知,在
完成窗口初始化后InitInstance()成員函數裡就調用了Game->Init(),也就是說Init()在窗口初始化后被調用。
  void CFrameWin::Init()
  {
   AfxMessageBox("Init");
  }
  Go()成員函數會不斷的被循環調用,它又調用了Update()和DestroyWindow()。Update()用于更新窗口,調用D
estroyWindow()則會結束應用程式。如果你把DestroyWindow()語句刪除掉,程式會不斷的循環。
  void CFrameWin::Go() // Game循環
  {
   AfxMessageBox("Go");
   Update();
   DestroyWindow();
  }
  Active()成員函數會在應用程式被擊活的時候被調用。
  void CFrameWin::Active() //窗口被激活
  {
   TRACE("Active");
   AfxMessageBox("Active");
  }
  這個程式並不做任何事,只是一個MFC框架。
2、初始化DirectX
  (DX8MFC1)
  本例將以第一章的MFC框架為基礎對CFrameWin類進行擴展。主要加入了DrawScene()、InitDirect3D(HWND hwn
d)和ShutdownDirect3D()三個函數。
  InitDirect3D(HWND hwnd)函數對Direct3D進行初始化︰
  HRESULT CFrameWin::InitDirect3D(HWND hwnd)
  {
   pID3D = Direct3DCreate8(D3D_SDK_VERSION);
   HRESULT hr;
   do
    {
     // we need the display mode so we can get
     // the properties of our back buffer
     D3DDISPLAYMODE d3ddm;
     hr = pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
     if(FAILED(hr))
      break;
     D3DPRESENT_PARAMETERS present;
     ZeroMemory(&present, sizeof(present));
     present.SwapEffect = D3DSWAPEFFECT_COPY;
     present.Windowed = TRUE;
     present.BackBufferFormat = d3ddm.Format;
     hr = pID3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice);
     if(FAILED(hr))
      break;
     // we do our own coloring, so disable lighting
     hr = pID3DDevice->SetRenderState(D3DRS_LIGHTING , FALSE);
     }
   while(0);
   return hr;
  }
  IDirect3D是我們首先要用到的界面,你可以這樣寫︰
  IDirect3D8 * pID3D = Direct3Dcreate8(D3D_SDK_VERSION);
  在你使用pID3D以前,請檢查pID3D是否為非空。你下一步通常是創建D3D設備,但在創建D3D設備之前你要調用
GetAdapterDisplayMode方法取得必須的訊息︰
  D3DDISPLAYMODE d3ddm; pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
  接下來是取得當前顯示模式參數。下面的參數是Surface格式。你可以用這些參數來創建一個D3DPRESENT_PARA
METERS架構︰
  D3DPRESENT_PARAMETERS present;
  ZeroMemory(&present, sizeof(present));
  present.SwapEffect = D3DSWAPEFFECT_COPY;
  present.Windowed = TRUE;
  present.BackBufferFormat = d3ddm.Format;
  D3DPRESENT_PARAMETERS描述了顯示器Surface的訊息,交換機製的類型,應用程式是窗口的還是全屏模式等信
息。在本例中, Surface是以拷貝方法代替頁面翻轉的,因為它是一個窗口模式的應用程式。把后台表面設置成與
當前顯示模式相匹配的格式,一個準備顯示的Surface可以Draw在后台表面上。
  現下你可以創建一個IDirect3DDevice8界面了︰
  pID3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice);
  這個函數有六個參數,幸運的是沒有一個是很複雜的。D3DADAPTER_DEFAULT告訴Direct3D使用主顯示器,只有
當你使用多顯示器時才是必須的。你可以使用一個數值來指定另外一個顯示器。調用IDirect3D的GetAdapterCount
將返回系統的適配器數目。
  第二個參數,D3DDEVTYPE_HAL,告訴Direct3D使用硬體加速。其它選項包括D3DDEVTYPE_REF和D3DDEVTYPE_SW,
通常你都會希望使用硬體加速的,但有時侯你可能會使用軟體加速進行測試。指定窗口取得焦點。如果是全屏應用
程式,你需要一個最頂層窗口。 D3DCREATE_SOFTWARE_VERTEXPROCESSING指定頂點處理類型。你也可以使用硬體加
速或是聯合類型,我不使用硬體加速為的是廣泛的兼容性。如果你想支持T&L, 則你必須使用硬體加速。最後兩個
參數很簡單,一個是你以前建立的,而pID3Ddevice是你現下要創建的IDirect3DDevice8界面。如果方法返回D3DER
R_NOTAVAILABLE,則你寫的參數是正確的,但你的設備不支持你指定的參數。
  最完美的是這個方法自動為你創建后台緩沖(back buffers)和深度緩沖(depth buffers) 。剪裁(Clippi
ng)作為后台表面(backface culling)被自動激活。燈光也被自動激活了,直到你定義頂點顏色之前,你可以禁
止使用燈光︰
  pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
  // DrawScene() 函數
  HRESULT CFrameWin::DrawScene()
  {
   HRESULT hr;
   do
    {
     // clear back buffer
     hr = pID3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0,63,0,0), 0, 0);
     if(FAILED(hr))
      break;
     // start drawing
     hr = pID3DDevice->BeginScene();
     if(FAILED(hr))
      break;
     // Put all drawing code here
     hr = pID3DDevice->EndScene();
     if(FAILED(hr))
      break;
     // flip back buffer to front
     hr = pID3DDevice->Present(NULL, NULL, NULL, NULL);
    }
   while(0);
   return hr;
   }
  Clear會填充你指定的緩沖區。你可以填充Z緩沖區、后台緩沖區或摸板緩沖區(stencil buffer)。在這個例
子中你將用綠色填充后台緩沖區。所以,我們設定D3DCLEAR_TARGET標誌和綠色。 在本例中BeginScene和EndScene
並沒有做什麼,但在以後的例子中我們會用到它的。這兩個函數是畫圖元時的例行公事代碼,這個函數不斷的翻轉
后台表面。我們可以不斷的在后台表面畫一些東西,然後把后台表面翻轉到前台表面。
  // ShutdownDirect3D() 函數
  void CFrameWin::ShutdownDirect3D()
  {
   HELPER_RELEASE(pTexture);
   HELPER_RELEASE(pIndexBuffer);
   HELPER_RELEASE(pStreamData);
   HELPER_RELEASE(pID3DDevice);
   HELPER_RELEASE(pID3D);
  }
  ShutdownDirect3D釋放所有的界面。將來你可能要加入額外的代碼來關閉Direct3D界面,但現下已經夠了。如
果你營運程式,你將得到一個綠色背景的窗口。你可以按“ESC”鍵來退出應用程式。
3、畫三角形
  (DX8MFC2)
  定義你的頂點格式,Direct3D引入了一種可變形頂點格式(flexible vertex format)(FVF)的概念。在FVF
中,你定義一個架構其中包括所需要的頂點組成部分。這個架構會隨著你的程式而改變,但在這裡你將初步把它定
義成這個樣子︰
  struct MYVERTEX
  {
   FLOAT x, y, z; // The transformed position
   FLOAT rhw; // 1.0 (reciprocal of homogeneous w)
   DWORD color; // The vertex color
  };
  示例的開始定義了一個頂點架構,頂點的名稱,和每一個三角形的頂點。在你的InitDirect3D函數中,你必須
創建一個頂點緩沖區︰
  int num_elems = sizeof(vertices) / sizeof(vertices[0]);
  pID3DDevice->CreateVertexBuffer(sizeof(MYVERTEX) * num_elems,
                  D3DUSAGE_WRITEONLY,
                  D3DFVF_XYZRHW|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &pStreamData);
  函數的第一個參數是頂點架構的位元組大小。在應用程式還不能讀取頂點之前,傳一個D3DUSAGE_WRITEONLY標記
給它。這裡可以有不同的標記來指定如何處理你的頂點,但現下你可以確信Direct3D已經能正確的工作了。下一步
,指定我們用的是什麼FVF格式。當你還沒有使用坐標系預轉換之前,指定為D3DFVF_XYZRHW標記。以後你使用自己
的矩陣坐標系轉換時,把它改成D3DFVF_XYZ。D3DFVF_DIFFUSE告訴Direct3D,我們將為每一個頂點指定顏色。
  D3DPOOL_DEFAULT指定內存的管理模式。最後一個參數是頂點緩沖區的指針, 在例子1中你已經定義了它,但
並沒有用上。 如果你不向頂點緩沖區填入有用數據的話,頂點緩沖區是沒有用的︰
  MYVERTEX *v;
  pStreamData->Lock(0, 0, (BYTE**)&v, 0);
  for(int ii = 0; ii < num_elems; ii++)
  {
   v[ii].x = vertices[ii].x;
   v[ii].y = vertices[ii].y;
   v[ii].z = vertices[ii].z;
   v[ii].rhw = vertices[ii].rhw;
   v[ii].color = vertices[ii].color;
  }
  pStreamData->Unlock();
  這是不難理解的,Lock返回一個你想寫入頂點數據的指針。下一步你從你的頂點陣列中拷貝數據。然後,反還
這個指針。這一對的調用可以告訴Direct3D你的FVF格式, 並設定頂點陣列為當前的活動頂點陣列。(你可以有多
個頂點陣列)。
  pID3DDevice->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
  pID3DDevice->SetStreamSource(0, pStreamData, sizeof(MYVERTEX));
  SetVertexShader告訴Direct3D使用與CreateVertexBuffer同樣的格式。
  SetStreamSource告訴Direct3D使用pStreamData作為當前頂點陣列,並取得所有元素的大小。
  你現下可以加入畫三角形的代碼了。在DrawScene()的BeginScene和EndScene之間加入如下代碼︰
  int num_elems = sizeof(vertices) / sizeof(vertices[0]);
  pID3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, num_elems / 3);
  D3DPT_TRIANGLELIST標記將命令Direct3D畫不連續的三角形。你指定從索引的第0個頂點開始, 指定所要畫的
三角形數目。如果正確的話,你會看到一個三角形畫在先前的綠色背景窗口上。
4、畫索引三角形
  (DX8MFC3)
  上一章的畫三角形模式營運效率是較低的,而實際上我們都會使用DrawIndexedPrimitive()而不是DrawPrimit
ive()。想一想,如果要畫兩個相連的三角形,共有四個頂點。用DrawIndexedPrimitive()畫要畫四個頂點,而用D
rawPrimitive()畫則要畫六個頂點。
  如果你可以頂點建立索引,你就可以用DrawIndexedPrimitive()畫三角形了。我們可以為一個三角形建立這樣
的索引︰
  WORD indices[] = { 0, 1, 2 };
  它表示三角形中,第一個頂點對應于頂點陣列的第0個頂點;三角形中,第二個頂點對應于頂點陣列的第1個頂
點;三角形中,第三個頂點對應于頂點陣列的第2個頂點; 要畫索引三角形,首先要建立索引緩沖︰
  num_elems = sizeof(indices) / sizeof(indices[0]);
  pID3DDevice->CreateIndexBuffer(sizeof(WORD) * num_elems,
                  D3DUSAGE_WRITEONLY, D3DFMT_INDEX16,
                  D3DPOOL_DEFAULT, &pIndexBuffer);
  第二步是用頂點填充這個索引緩沖︰
  WORD *pIndex;
  pIndexBuffer->Lock(0, 0, (BYTE **)&pIndex, 0);
  for(ii = 0; ii < num_elems; ii++)
  {
   pIndex[ii] = indices[ii];
  }
  pIndexBuffer->Unlock();
  設定索引緩沖︰
  pID3DDevice->SetIndices(pIndexBuffer, 0);
  把DrawScene()的相應的pID3DDevice->DrawPrimitive(...)換成︰
  pID3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, sizeof(indices) / sizeof(indices[0]),
                    0, sizeof(indices) / sizeof(indices[0]) / 3);
  營運程式的到的還是一個三角形。
5、加入帖圖
  (DX8MFC4)
  首先,在MYVERTEX架構中加入帖圖坐標系tu和tv,並給頂點陣列賦以適當的值。
  下一步,設置你的帖圖︰
  D3DXCreateTextureFromFile(pID3DDevice, "dx5_logo.bmp", &pTexture);
  pID3DDevice->SetTexture(0, pTexture);
  其中的“dx5_logo.bmp”指的是帖圖文件,你可以用其他的文件代替它,營運程式你會看到一個帶帖圖的三角
形。
6、帖圖立方體
  (DX8MFC5)
  現下樣我們來進入三維的世界吧﹗這裡你要啟用Z緩沖(z-buffer), 設置立方體的材質,世界坐標系和投影坐
標系。啟用Z緩沖(z-buffer),你要在D3DPRESENT_PARAMETERS架構中加入︰
  present.EnableAutoDepthStencil = TRUE;
  present.AutoDepthStencilFormat = D3DFMT_D16;
  這裡告訴DirectX8使用16位的Z緩沖,下一步︰
  pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
  到這裡Z緩沖已經設置完成。最後你還要在DrawScene()中調用清除Z緩沖內容的代碼︰
  pID3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
           D3DCOLOR_RGBA(0,63,0,0), 1.0, 0);
  // MYVERTEX架構改成︰
  struct MYVERTEX
  {
   FLOAT x, y, z; // The transformed position
   DWORD color; // The vertex color
   FLOAT tu, tv; // Texture coordinates
  };
  在InitDirect3D()也作了相應改動,具體可見源代碼。Direct3D中有多種矩陣,在這裡只使用其中的三個︰世
界、視圖和投影矩陣。世界矩陣變換會把正方體放在世界坐標系中,視圖矩陣變換把正方體放在可視空間內,投影
矩陣使正方體看起來有深度感。BuildMatrices()函數將建立這三個矩陣︰
  void CFrameWin::BuildMatrices()
  {
   D3DXMATRIX matrix;
   D3DXMatrixRotationY(&matrix, timeGetTime() / 1000.0f);
   pID3DDevice->SetTransform(D3DTS_WORLD, &matrix);
   D3DXMatrixLookAtLH(&matrix,
             &D3DXVECTOR3(0.0f, 3.0f, -5.0f), // 攝像機的空間位置
             &D3DXVECTOR3(0.0f, 0.0f, 0.0f), // 攝象機觀察點
             &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // 攝象機向上方向矢量
   pID3DDevice->SetTransform(D3DTS_VIEW, &matrix); // 設置我們的平截面為45度角
   D3DXMatrixPerspectiveFovLH(&matrix, D3DX_PI / 4, 4.0f / 3.0f, 1.0f, 100.0f);
   pID3DDevice->SetTransform(D3DTS_PROJECTION, &matrix);
  }
  營運本章的例子你將看到一個旋轉的正方體。
  你可以從gamedev.363.net下載本文所有例子的源程式,或透過E-Mail向本文作者索取。
作者Blog︰http://blog.csdn.net/EA/

eager 發表在 痞客邦 留言(0) 人氣()


作者Blog︰http://blog.csdn.net/EA/
=======================================
1、MFC框架
  (DX8MFC)
  這裡的MFC框架指的是一個符合遊戲開發應用的框架,當然你也可以寫一個符合你要求的MFC框架。如果你對MF
C比較熟悉的話可以直接從第二章開始閱讀。本框架是以後幾個例子的基礎,如果你對MFC不是很了解的話,就要認
真閱讀本章,以求對這個MFC框架有一個深入的了解。
  框架中包括兩個類︰
  CDX8MFCApp類和CFrameWin類,CDX8MFCApp類是應用程式類,CFrameWin類是框架的主類,以後我們的大部分代
碼都是從這裡擴展的。首先來看一看CDX8MFCApp類,它包括CDX8MFCApp()、ExitInstance()、InitInstance()、On
Idle(LONG lCount)等成員函數和一個Game對象。
  InitInstance()成員函數在程式初始化時就被調用,在這裡我建立了一個窗口︰
  ExitInstance()成員函數在程式終止時被調用,在這裡我們釋放一些對象和指針︰
  OnIdle(LONG lCount)成員函數會在沒有Windows消息要處理的時候被調用,也就是說OnIdle()成員函數會不斷
的被調用,這正好被我們用作遊戲循環。
  BOOL CDX8MFCApp::InitInstance()
  {
   // The one and only window has been initialized, so show and update it.
   m_pMainWnd = new CFrameWin();
   m_pMainWnd->ShowWindow(m_nCmdShow);
   m_pMainWnd->UpdateWindow();
   Game = (CFrameWin*) m_pMainWnd;
   Game->Init();
   return TRUE;
  }
  ExitInstance()成員函數在程式終止時被調用,在這裡我們釋放一些對象和指針︰
  int CDX8MFCApp::ExitInstance()
  {
   // TODO: Add your specialized code here and/or call the base class
   Game->End();
   delete Game;
   return CWinApp::ExitInstance();
  }
  OnIdle(LONG lCount)成員函數會在沒有Windows消息要處理的時候被調用,也就是說OnIdle()成員函數會不斷
的被調用,這正好被我們用作遊戲循環。
  BOOL CDX8MFCApp::OnIdle(LONG lCount)
  {
   // TODO: Add your specialized code here and/or call the base class
   if(Game->window_active==TRUE)
    {
     Game->Active();
     Game->window_active=FALSE;
    }
   Game->Go();
   return TRUE;
  }
  Game對象是一個CFrameWin類指針,我們在InitInstance()成員函數中創建了一個CFrameWin對象並把CFrameWi
n對象的指針值賦給Game。下面我們來看一看CFrameWin類, 它包括Active()、End()、Go()、Init()、Update()等
成員函數。
  Init()成員函數,你可以在這裡做一些自己的初始化。回顧CDX8MFCApp類的InitInstance()成員函數可知,在
完成窗口初始化后InitInstance()成員函數裡就調用了Game->Init(),也就是說Init()在窗口初始化后被調用。
  void CFrameWin::Init()
  {
   AfxMessageBox("Init");
  }
  Go()成員函數會不斷的被循環調用,它又調用了Update()和DestroyWindow()。Update()用于更新窗口,調用D
estroyWindow()則會結束應用程式。如果你把DestroyWindow()語句刪除掉,程式會不斷的循環。
  void CFrameWin::Go() // Game循環
  {
   AfxMessageBox("Go");
   Update();
   DestroyWindow();
  }
  Active()成員函數會在應用程式被擊活的時候被調用。
  void CFrameWin::Active() //窗口被激活
  {
   TRACE("Active");
   AfxMessageBox("Active");
  }
  這個程式並不做任何事,只是一個MFC框架。
2、初始化DirectX
  (DX8MFC1)
  本例將以第一章的MFC框架為基礎對CFrameWin類進行擴展。主要加入了DrawScene()、InitDirect3D(HWND hwn
d)和ShutdownDirect3D()三個函數。
  InitDirect3D(HWND hwnd)函數對Direct3D進行初始化︰
  HRESULT CFrameWin::InitDirect3D(HWND hwnd)
  {
   pID3D = Direct3DCreate8(D3D_SDK_VERSION);
   HRESULT hr;
   do
    {
     // we need the display mode so we can get
     // the properties of our back buffer
     D3DDISPLAYMODE d3ddm;
     hr = pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
     if(FAILED(hr))
      break;
     D3DPRESENT_PARAMETERS present;
     ZeroMemory(&present, sizeof(present));
     present.SwapEffect = D3DSWAPEFFECT_COPY;
     present.Windowed = TRUE;
     present.BackBufferFormat = d3ddm.Format;
     hr = pID3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice);
     if(FAILED(hr))
      break;
     // we do our own coloring, so disable lighting
     hr = pID3DDevice->SetRenderState(D3DRS_LIGHTING , FALSE);
     }
   while(0);
   return hr;
  }
  IDirect3D是我們首先要用到的界面,你可以這樣寫︰
  IDirect3D8 * pID3D = Direct3Dcreate8(D3D_SDK_VERSION);
  在你使用pID3D以前,請檢查pID3D是否為非空。你下一步通常是創建D3D設備,但在創建D3D設備之前你要調用
GetAdapterDisplayMode方法取得必須的訊息︰
  D3DDISPLAYMODE d3ddm; pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
  接下來是取得當前顯示模式參數。下面的參數是Surface格式。你可以用這些參數來創建一個D3DPRESENT_PARA
METERS架構︰
  D3DPRESENT_PARAMETERS present;
  ZeroMemory(&present, sizeof(present));
  present.SwapEffect = D3DSWAPEFFECT_COPY;
  present.Windowed = TRUE;
  present.BackBufferFormat = d3ddm.Format;
  D3DPRESENT_PARAMETERS描述了顯示器Surface的訊息,交換機製的類型,應用程式是窗口的還是全屏模式等信
息。在本例中, Surface是以拷貝方法代替頁面翻轉的,因為它是一個窗口模式的應用程式。把后台表面設置成與
當前顯示模式相匹配的格式,一個準備顯示的Surface可以Draw在后台表面上。
  現下你可以創建一個IDirect3DDevice8界面了︰
  pID3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
            D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice);
  這個函數有六個參數,幸運的是沒有一個是很複雜的。D3DADAPTER_DEFAULT告訴Direct3D使用主顯示器,只有
當你使用多顯示器時才是必須的。你可以使用一個數值來指定另外一個顯示器。調用IDirect3D的GetAdapterCount
將返回系統的適配器數目。
  第二個參數,D3DDEVTYPE_HAL,告訴Direct3D使用硬體加速。其它選項包括D3DDEVTYPE_REF和D3DDEVTYPE_SW,
通常你都會希望使用硬體加速的,但有時侯你可能會使用軟體加速進行測試。指定窗口取得焦點。如果是全屏應用
程式,你需要一個最頂層窗口。 D3DCREATE_SOFTWARE_VERTEXPROCESSING指定頂點處理類型。你也可以使用硬體加
速或是聯合類型,我不使用硬體加速為的是廣泛的兼容性。如果你想支持T&L, 則你必須使用硬體加速。最後兩個
參數很簡單,一個是你以前建立的,而pID3Ddevice是你現下要創建的IDirect3DDevice8界面。如果方法返回D3DER
R_NOTAVAILABLE,則你寫的參數是正確的,但你的設備不支持你指定的參數。
  最完美的是這個方法自動為你創建后台緩沖(back buffers)和深度緩沖(depth buffers) 。剪裁(Clippi
ng)作為后台表面(backface culling)被自動激活。燈光也被自動激活了,直到你定義頂點顏色之前,你可以禁
止使用燈光︰
  pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
  // DrawScene() 函數
  HRESULT CFrameWin::DrawScene()
  {
   HRESULT hr;
   do
    {
     // clear back buffer
     hr = pID3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0,63,0,0), 0, 0);
     if(FAILED(hr))
      break;
     // start drawing
     hr = pID3DDevice->BeginScene();
     if(FAILED(hr))
      break;
     // Put all drawing code here
     hr = pID3DDevice->EndScene();
     if(FAILED(hr))
      break;
     // flip back buffer to front
     hr = pID3DDevice->Present(NULL, NULL, NULL, NULL);
    }
   while(0);
   return hr;
   }
  Clear會填充你指定的緩沖區。你可以填充Z緩沖區、后台緩沖區或摸板緩沖區(stencil buffer)。在這個例
子中你將用綠色填充后台緩沖區。所以,我們設定D3DCLEAR_TARGET標誌和綠色。 在本例中BeginScene和EndScene
並沒有做什麼,但在以後的例子中我們會用到它的。這兩個函數是畫圖元時的例行公事代碼,這個函數不斷的翻轉
后台表面。我們可以不斷的在后台表面畫一些東西,然後把后台表面翻轉到前台表面。
  // ShutdownDirect3D() 函數
  void CFrameWin::ShutdownDirect3D()
  {
   HELPER_RELEASE(pTexture);
   HELPER_RELEASE(pIndexBuffer);
   HELPER_RELEASE(pStreamData);
   HELPER_RELEASE(pID3DDevice);
   HELPER_RELEASE(pID3D);
  }
  ShutdownDirect3D釋放所有的界面。將來你可能要加入額外的代碼來關閉Direct3D界面,但現下已經夠了。如
果你營運程式,你將得到一個綠色背景的窗口。你可以按“ESC”鍵來退出應用程式。
3、畫三角形
  (DX8MFC2)
  定義你的頂點格式,Direct3D引入了一種可變形頂點格式(flexible vertex format)(FVF)的概念。在FVF
中,你定義一個架構其中包括所需要的頂點組成部分。這個架構會隨著你的程式而改變,但在這裡你將初步把它定
義成這個樣子︰
  struct MYVERTEX
  {
   FLOAT x, y, z; // The transformed position
   FLOAT rhw; // 1.0 (reciprocal of homogeneous w)
   DWORD color; // The vertex color
  };
  示例的開始定義了一個頂點架構,頂點的名稱,和每一個三角形的頂點。在你的InitDirect3D函數中,你必須
創建一個頂點緩沖區︰
  int num_elems = sizeof(vertices) / sizeof(vertices[0]);
  pID3DDevice->CreateVertexBuffer(sizeof(MYVERTEX) * num_elems,
                  D3DUSAGE_WRITEONLY,
                  D3DFVF_XYZRHW|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &pStreamData);
  函數的第一個參數是頂點架構的位元組大小。在應用程式還不能讀取頂點之前,傳一個D3DUSAGE_WRITEONLY標記
給它。這裡可以有不同的標記來指定如何處理你的頂點,但現下你可以確信Direct3D已經能正確的工作了。下一步
,指定我們用的是什麼FVF格式。當你還沒有使用坐標系預轉換之前,指定為D3DFVF_XYZRHW標記。以後你使用自己
的矩陣坐標系轉換時,把它改成D3DFVF_XYZ。D3DFVF_DIFFUSE告訴Direct3D,我們將為每一個頂點指定顏色。
  D3DPOOL_DEFAULT指定內存的管理模式。最後一個參數是頂點緩沖區的指針, 在例子1中你已經定義了它,但
並沒有用上。 如果你不向頂點緩沖區填入有用數據的話,頂點緩沖區是沒有用的︰
  MYVERTEX *v;
  pStreamData->Lock(0, 0, (BYTE**)&v, 0);
  for(int ii = 0; ii < num_elems; ii++)
  {
   v[ii].x = vertices[ii].x;
   v[ii].y = vertices[ii].y;
   v[ii].z = vertices[ii].z;
   v[ii].rhw = vertices[ii].rhw;
   v[ii].color = vertices[ii].color;
  }
  pStreamData->Unlock();
  這是不難理解的,Lock返回一個你想寫入頂點數據的指針。下一步你從你的頂點陣列中拷貝數據。然後,反還
這個指針。這一對的調用可以告訴Direct3D你的FVF格式, 並設定頂點陣列為當前的活動頂點陣列。(你可以有多
個頂點陣列)。
  pID3DDevice->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
  pID3DDevice->SetStreamSource(0, pStreamData, sizeof(MYVERTEX));
  SetVertexShader告訴Direct3D使用與CreateVertexBuffer同樣的格式。
  SetStreamSource告訴Direct3D使用pStreamData作為當前頂點陣列,並取得所有元素的大小。
  你現下可以加入畫三角形的代碼了。在DrawScene()的BeginScene和EndScene之間加入如下代碼︰
  int num_elems = sizeof(vertices) / sizeof(vertices[0]);
  pID3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, num_elems / 3);
  D3DPT_TRIANGLELIST標記將命令Direct3D畫不連續的三角形。你指定從索引的第0個頂點開始, 指定所要畫的
三角形數目。如果正確的話,你會看到一個三角形畫在先前的綠色背景窗口上。
4、畫索引三角形
  (DX8MFC3)
  上一章的畫三角形模式營運效率是較低的,而實際上我們都會使用DrawIndexedPrimitive()而不是DrawPrimit
ive()。想一想,如果要畫兩個相連的三角形,共有四個頂點。用DrawIndexedPrimitive()畫要畫四個頂點,而用D
rawPrimitive()畫則要畫六個頂點。
  如果你可以頂點建立索引,你就可以用DrawIndexedPrimitive()畫三角形了。我們可以為一個三角形建立這樣
的索引︰
  WORD indices[] = { 0, 1, 2 };
  它表示三角形中,第一個頂點對應于頂點陣列的第0個頂點;三角形中,第二個頂點對應于頂點陣列的第1個頂
點;三角形中,第三個頂點對應于頂點陣列的第2個頂點; 要畫索引三角形,首先要建立索引緩沖︰
  num_elems = sizeof(indices) / sizeof(indices[0]);
  pID3DDevice->CreateIndexBuffer(sizeof(WORD) * num_elems,
                  D3DUSAGE_WRITEONLY, D3DFMT_INDEX16,
                  D3DPOOL_DEFAULT, &pIndexBuffer);
  第二步是用頂點填充這個索引緩沖︰
  WORD *pIndex;
  pIndexBuffer->Lock(0, 0, (BYTE **)&pIndex, 0);
  for(ii = 0; ii < num_elems; ii++)
  {
   pIndex[ii] = indices[ii];
  }
  pIndexBuffer->Unlock();
  設定索引緩沖︰
  pID3DDevice->SetIndices(pIndexBuffer, 0);
  把DrawScene()的相應的pID3DDevice->DrawPrimitive(...)換成︰
  pID3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, sizeof(indices) / sizeof(indices[0]),
                    0, sizeof(indices) / sizeof(indices[0]) / 3);
  營運程式的到的還是一個三角形。
5、加入帖圖
  (DX8MFC4)
  首先,在MYVERTEX架構中加入帖圖坐標系tu和tv,並給頂點陣列賦以適當的值。
  下一步,設置你的帖圖︰
  D3DXCreateTextureFromFile(pID3DDevice, "dx5_logo.bmp", &pTexture);
  pID3DDevice->SetTexture(0, pTexture);
  其中的“dx5_logo.bmp”指的是帖圖文件,你可以用其他的文件代替它,營運程式你會看到一個帶帖圖的三角
形。
6、帖圖立方體
  (DX8MFC5)
  現下樣我們來進入三維的世界吧﹗這裡你要啟用Z緩沖(z-buffer), 設置立方體的材質,世界坐標系和投影坐
標系。啟用Z緩沖(z-buffer),你要在D3DPRESENT_PARAMETERS架構中加入︰
  present.EnableAutoDepthStencil = TRUE;
  present.AutoDepthStencilFormat = D3DFMT_D16;
  這裡告訴DirectX8使用16位的Z緩沖,下一步︰
  pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
  到這裡Z緩沖已經設置完成。最後你還要在DrawScene()中調用清除Z緩沖內容的代碼︰
  pID3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
           D3DCOLOR_RGBA(0,63,0,0), 1.0, 0);
  // MYVERTEX架構改成︰
  struct MYVERTEX
  {
   FLOAT x, y, z; // The transformed position
   DWORD color; // The vertex color
   FLOAT tu, tv; // Texture coordinates
  };
  在InitDirect3D()也作了相應改動,具體可見源代碼。Direct3D中有多種矩陣,在這裡只使用其中的三個︰世
界、視圖和投影矩陣。世界矩陣變換會把正方體放在世界坐標系中,視圖矩陣變換把正方體放在可視空間內,投影
矩陣使正方體看起來有深度感。BuildMatrices()函數將建立這三個矩陣︰
  void CFrameWin::BuildMatrices()
  {
   D3DXMATRIX matrix;
   D3DXMatrixRotationY(&matrix, timeGetTime() / 1000.0f);
   pID3DDevice->SetTransform(D3DTS_WORLD, &matrix);
   D3DXMatrixLookAtLH(&matrix,
             &D3DXVECTOR3(0.0f, 3.0f, -5.0f), // 攝像機的空間位置
             &D3DXVECTOR3(0.0f, 0.0f, 0.0f), // 攝象機觀察點
             &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // 攝象機向上方向矢量
   pID3DDevice->SetTransform(D3DTS_VIEW, &matrix); // 設置我們的平截面為45度角
   D3DXMatrixPerspectiveFovLH(&matrix, D3DX_PI / 4, 4.0f / 3.0f, 1.0f, 100.0f);
   pID3DDevice->SetTransform(D3DTS_PROJECTION, &matrix);
  }
  營運本章的例子你將看到一個旋轉的正方體。
  你可以從gamedev.363.net下載本文所有例子的源程式,或透過E-Mail向本文作者索取。
作者Blog︰http://blog.csdn.net/EA/

eager 發表在 痞客邦 留言(0) 人氣()

Scan,是一切入侵的基礎,掃描探測一台主機包括是為了確定主機是否活動、主機系統、正在使用哪些端口、提供了哪些服務、相關服務的軟體版本等等,對這些內容的探測就是為了"對症下藥"。對主機的探測工具非常多,比如大名鼎鼎的nmap、netcat、superscan,以及國內的X-Scanner等等。
ICMP協議──PING是最常用的,也是最簡單的探測手段,用來判斷目標是否活動。實際上Ping是向目標發送一個要求回顯(Type = 8)的ICMP數據報,當主機得到請求后,再返回一個回顯(Type = 0)數據報。而且Ping 程式一般是直接實現下系統內核中的,而不是一個用戶進程。Ping是最基本的探測手段,Ping Sweep(Ping掃射)就是對一個網段進行大範圍的Ping,由此確定這個網段的網路運作情況,比如著名的fping工具就是進行Ping掃射的。
不過現下連基本的個人防火牆都對Ping做了限制,這個也太基本了。如果透過防火牆,如何獲得最理想的目標圖,也是很多人整天思考的問題。我們這裡介紹的一些掃描技術就是要儘可能地繞過一些安全防護設備,並且盡量保護自己,同時達到我們需要的目的。
  一、高級ICMP掃描技術
  Ping就是利用ICMP協議走的,高級的ICMP掃描技術主要是利用ICMP協議最基本的用途︰報錯。根據網路協議,如果按照協議出現了錯誤,那么接收端將產生一個ICMP的錯誤報文。這些錯誤報文並不是主動發送的,而是由於錯誤,根據協議自動產生。
  當IP數據報出現checksum和版本的錯誤的時候,目標主機將拋棄這個數據報,如果是checksum出現錯誤,那么路由器就直接丟棄這個數據報了。有些主機比如AIX、HP-UX等,是不會發送ICMP的Unreachable數據報的。
  我們利用下面這些特性︰
  1、向目標主機發送一個只有IP頭的IP數據包,目標將返回Destination Unreachable的ICMP錯誤報文。
  2、向目標主機發送一個壞IP數據報,比如,不正確的IP頭長度,目標主機將返回Parameter Problem的ICMP錯誤報文。
  3、當數據包分片但是,卻沒有給接收端足夠的分片,接收端分片組裝超時會發送分片組裝超時的ICMP數據報。
  向目標主機發送一個IP數據報,但是協議項是錯誤的,比如協議項不可用,那么目標將返回Destination Unreachable的ICMP報文,但是如果是在目標主機前有一個防火牆或者一個其他的過濾裝置,可能過濾掉提出的要求,從而接收不到任何回應。可以使用一個非常大的協議數字來作為IP頭部的協議內容,而且這個協議數字至少在今天還沒有被使用,應該主機一定會返回Unreachable,如果沒有Unreachable的ICMP數據報返回錯誤提示,那么就說明被防火牆或者其他設備過濾了,我們也可以用這個辦法來探測是否有防火牆或者其他過濾設備存在。
  利用IP的協議項來探測主機正在使用哪些協議,我們可以把IP頭的協議項改變,因為是8位的,有256種可能。透過目標返回的ICMP錯誤報文,來作判斷哪些協議在使用。如果返回Destination Unreachable,那么主機是沒有使用這個協議的,相反,如果什麼都沒有返回的話,主機可能使用這個協議,但是也可能是防火牆等過濾掉了。NMAP的IP Protocol scan也就是利用這個原理。
  利用IP分片造成組裝超時ICMP錯誤消息,同樣可以來達到我們的探測目的。當主機接收到丟失分片的數據報,並且在一定時間內沒有接收到丟失的數據報,就會丟棄整個包,並且發送ICMP分片組裝超時錯誤給原發送端。我們可以利用這個特性製造分片的數據包,然後等待ICMP組裝超時錯誤消息。可以對UDP分片,也可以對TCP甚至ICMP數據包進行分片,只要不讓目標主機獲得完整的數據包就行了,當然,對于UDP這種非連接的不可靠協議來說,如果我們沒有接收到超時錯誤的ICMP返回報,也有可能時由於線路或者其他問題在傳輸過程中丟失了。
  我們能夠利用上面這些特性來得到防火牆的ACL(access list),甚至用這些特性來獲得整個網路拓撲架構。如果我們不能從目標得到Unreachable報文或者分片組裝超時錯誤報文,可以作下面的判斷︰
  1、防火牆過濾了我們發送的協議類型
  2、防火牆過濾了我們指定的端口
  3、防火牆阻塞ICMP的Destination Unreachable或者Protocol Unreachable錯誤消息。
  4、防火牆對我們指定的主機進行了ICMP錯誤報文的阻塞。
  二、高級TCP掃描技術
  最基本的利用TCP掃描就是使用connect(),這個很容易實現,如果目標主機能夠connect,就說明一個相應的端口打開。不過,這也是最原始和最先被防護工具拒絕的一種。
  在高級的TCP掃描技術中主要利用TCP連接的三次握手特性和TCP數據頭中的標誌位來進行,也就是所謂的半開掃描。
  先認識一下TCP數據報頭的這六個標誌位。
  URG︰(Urgent Pointer field significant)緊急指針。用到的時候值為1,用來處理避免TCP數據流中斷
  ACK︰(Acknowledgment field significant)置1時表示確認號(Acknowledgment Number)為合法,為0的時候表示數據段不包含確認訊息,確認號被忽略。
  PSH︰(Push Function),PUSH標誌的數據,置1時請求的數據段在接收方得到后就可直接送到應用程式,而不必等到緩沖區滿時才傳送。
  RST︰(Reset the connection)用于複位因某種原因引起出現的錯誤連接,也用來拒絕非法數據和請求。如果接收到RST位時候,通常發生了某些錯誤。
  SYN︰(Synchronize sequence numbers)用來建立連接,在連接請求中,SYN=1,ACK=0,連接附應時, SYN=1,ACK=1。即,SYN和ACK來區分Connection Request和Connection Accepted。
  FIN︰(No more data from sender)用來釋放連接,表明發送方已經沒有數據發送了。
  TCP協議連接的三次握手過程是這樣的︰
  首先客戶端(請求方)在連接請求中,發送SYN=1,ACK=0的TCP數據包給伺服器端(接收請求端),表示要求同伺服器端建立一個連接;然後如果伺服器端附應這個連接,就返回一個SYN=1,ACK=1的數據報給客戶端,表示伺服器端同意這個連接,並要求客戶端確認;最後客戶端就再發送SYN=0,ACK=1的數據包給伺服器端,表示確認建立連接。
  我們就利用這些標誌位和TCP協議連接的三次握手特性來進行掃描探測。
  SYN 掃描
  這種掃描模式也被稱為"半打開" 掃描,因為利用了TCP協議連接的第一步,並且沒有建立一個完整的TCP連接。實現辦法是向遠端主機某端口發送一個只有SYN標誌位的TCP數據報,如果主機回饋一個SYN || ACK數據包,那么,這個主機正在監聽該端口,如果回饋的是RST數據包,說明,主機沒有監聽該端口。在X-Scanner 上就有SYN的選擇項。
  ACK 掃描
  發送一個只有ACK標誌的TCP數據報給主機,如果主機回饋一個TCP RST數據報來,那么這個主機是存在的。也可以透過這種技術來確定對方防火牆是否是簡單的分組過濾,還是一個基于狀態的防火牆。
  FIN
  對某端口發送一個TCP FIN數據報給遠端主機。如果主機沒有任何回饋,那么這個主機是存在的,而且正在監聽這個端口;主機回饋一個TCP RST回來,那么說明該主機是存在的,但是沒有監聽這個端口。
  NULL
  即發送一個沒有任何標誌位的TCP包,根據RFC793,如果目標主機的相應端口是關閉的話,應該發送回一個RST數據包。
  FIN+URG+PUSH
  向目標主機發送一個Fin、URG和PUSH分組,根據RFC793,如果目標主機的相應端口是關閉的,那么應該返回一個RST標誌。
  上面這些辦法可以繞過一些防火牆,從而得到防火牆后面的主機訊息,當然,是在不被欺騙的情況下的。這些方法還有一個好處就是比較難于被記錄,有的辦法即使在用netstat命令上也根本顯示不出來,而且一般的安全防護設備也根本不記錄這些內容,這樣能夠更好地隱藏自己。
三、高級UDP掃描技術
  在UDP實現的掃描中,多是了利用和ICMP進行的組合進行,這在ICMP中以及提及了。還有一些特殊的就是UDP回饋,比如SQL SERVER,對其1434端口發送‘x02'或者‘x03'就能夠探測得到其連接端口。
  下面這段程式就是一個TCP探測的例子,當然,並沒有做得完美,因為沒有接收部分,而在WIN2000下實際就是一個選擇性的SNIFFER,呵呵,大家可以使用其他的SNIFFER來實現同樣的目的。也可以改變下面的程式只發送IP包,利用ICMP特性來實現探測。
#include 〈stdio.h>;
#include 〈winsock2.h>;
#include 〈ws2tcpip.h>;
#define SOURCE_PORT 7234
#define MAX_RECEIVEBYTE 255
typedef struct ip_hdr //定義IP首部
{
unsigned char h_verlen; //4位首部長度,4位IP版本號
unsigned char tos; //8位服務類型TOS
unsigned short total_len; //16位總長度(位元組)
unsigned short ident; //16位標識
unsigned short frag_and_flags; //3位標誌位
unsigned char ttl; //8位生存時間 TTL
unsigned char proto; //8位協議 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校驗和
unsigned int sourceIP; //32位源IP位址
unsigned int destIP; //32位目的IP位址
}IPHEADER;
typedef struct tsd_hdr //定義TCP偽首部
{
unsigned long saddr; //源位址
unsigned long daddr; //到達站址
char mbz;
char ptcl; //協議類型
unsigned short tcpl; //TCP長度
}PSDHEADER;
typedef struct tcp_hdr //定義TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列號
unsigned int th_ack; //32位確認號
unsigned char th_lenres; //4位首部長度/6位保留字
unsigned char th_flag; //6位標誌位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校驗和
USHORT th_urp; //16位緊急數據偏移量
}TCPHEADER;
//CheckSum:計算校驗和的子函數
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >;1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >;>; 16) + (cksum &; 0xffff);
cksum += (cksum >;>;16);
return (USHORT)(~cksum);
}
void usage()
{
printf(";******************************************
";);
printf(";TCPPing
";);
printf("; Written by Refdom
";);
printf("; Email: refdom@263.net
";);
printf(";Useage: TCPPing.exe Target_ip Target_port
";);
printf(";*******************************************
";);
}
int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;
char szSendBuf[60]={0};
BOOL flag;
int rect,nTimeOver;
usage();
if (argc!= 3)
{ return false; }
if (WSAStartup(MAKEWORD(2,2), &;WSAData)!=0)
{
printf(";WSAStartup Error!
";);
return false;
}
if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
printf(";Socket Setup Error!
";);
return false;
}
flag=true;
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&;flag,sizeof(flag))==SOCKET_ERROR)
{
printf(";setsockopt IP_HDRINCL error!
";);
return false;
}
nTimeOver=1000;
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&;nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)
{
printf(";setsockopt SO_SNDTIMEO error!
";);
return false;
}
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(atoi(argv[2]));
addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);
//
//
//填充IP首部
ipHeader.h_verlen=(4〈〈4 | sizeof(ipHeader)/sizeof(unsigned long));
// ipHeader.tos=0;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
ipHeader.ident=1;
ipHeader.frag_and_flags=0;
ipHeader.ttl=128;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.sourceIP=inet_addr(";本地位址";);
ipHeader.destIP=inet_addr(argv[1]);
//填充TCP首部
tcpHeader.th_dport=htons(atoi(argv[2]));
tcpHeader.th_sport=htons(SOURCE_PORT); //源端口號
tcpHeader.th_seq=htonl(0x12345678);
tcpHeader.th_ack=0;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4〈〈4|0);
tcpHeader.th_flag=2; //修改這裡來實現不同的標誌位探測,2是SYN,1是FIN,16是ACK探測 等等
tcpHeader.th_win=htons(512);
tcpHeader.th_urp=0;
tcpHeader.th_sum=0;
psdHeader.saddr=ipHeader.sourceIP;
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));
//計算校驗和
memcpy(szSendBuf, &;psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &;tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &;ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &;tcpHeader, sizeof(tcpHeader));
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &;ipHeader, sizeof(ipHeader));
rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),
0, (struct sockaddr*)&;addr_in, sizeof(addr_in));
if (rect==SOCKET_ERROR)
{
printf(";send error!:%d
";,WSAGetLastError());
return false;
}
else
printf(";send ok!
";);
closesocket(sock);
WSACleanup();
return 0;
}

eager 發表在 痞客邦 留言(0) 人氣()

  • Feb 24 Thu 2005 21:43
  • 未來

網路上看到的文章中有好句子
轉錄一下
未來是看得見摸得著的,她隱藏在你前面的濃霧中,經常給你這樣那樣的以外,讓你無法認情自己的方向。
你甚至不知道下一刻你會在什麼地方,雖然這一刻你還坐在電腦前面看著這篇東西。
對于未來不再有把握。雖然我知道我的方向始終沒有變過,但是我卻再沒有那種對于成功的十足的自信和把握。
也許,未來就像一座山,你在很遠的地方,能夠很清晰的看見,而離它越近,卻越難以看清。
直到有一天你忽然發現你已經到了山頂上,才知道人生是如此精彩。沒有意外的人生又怎么會是真實的呢?

eager 發表在 痞客邦 留言(0) 人氣()

  • Feb 24 Thu 2005 02:15
  • 未來

網路上看到的文章中有好句子
轉錄一下
未來是看得見摸得著的,她隱藏在你前面的濃霧中,經常給你這樣那樣的以外,讓你無法認情自己的方向。
你甚至不知道下一刻你會在什麼地方,雖然這一刻你還坐在電腦前面看著這篇東西。
對于未來不再有把握。雖然我知道我的方向始終沒有變過,但是我卻再沒有那種對于成功的十足的自信和把握。
也許,未來就像一座山,你在很遠的地方,能夠很清晰的看見,而離它越近,卻越難以看清。
直到有一天你忽然發現你已經到了山頂上,才知道人生是如此精彩。沒有意外的人生又怎么會是真實的呢?

eager 發表在 痞客邦 留言(0) 人氣()

最近都在下雨
白天下,晚上下,就連半夜也下
真煩阿...........害我只能躲在家裡玩遊戲....
之前住在台中,花蓮都沒這麼常下,頂多一個月下個三四天(台中最棒了,不常下雨還都不會缺水)
一到台北,嘩啦啦星期就下了五天
想要出去晃都不行,真希望太陽公公這星期可以出來透透氣阿
殘念...我這周還想去資訊展阿

eager 發表在 痞客邦 留言(0) 人氣()

最近都在下雨
白天下,晚上下,就連半夜也下
真煩阿...........害我只能躲在家裡玩遊戲....
之前住在台中,花蓮都沒這麼常下,頂多一個月下個三四天(台中最棒了,不常下雨還都不會缺水)
一到台北,嘩啦啦星期就下了五天
想要出去晃都不行,真希望太陽公公這星期可以出來透透氣阿
殘念...我這周還想去資訊展阿

eager 發表在 痞客邦 留言(0) 人氣()

Blog Stats
⚠️

成人內容提醒

本部落格內容僅限年滿十八歲者瀏覽。
若您未滿十八歲,請立即離開。

已滿十八歲者,亦請勿將內容提供給未成年人士。