九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

GNU的幽默


GNU的幽默

write by 九天雁翎(JTianLing) -- www.jtianling.com

GNU从名字开始幽默,GNU是GNU Not Unix的缩写。。。。-_-!

 

其主页上专门有一条GNU FUN:

http://www.gnu.org/fun/fun.html

其中最后的 Disclaim 如下:

Humor Submission Guidelines

Our policy for the humor page is that we will include something if all of these are true:

  1. It should be funny.
  2. It has no copyright problems.
  3. It is not libelous.
  4. It won't offend most ordinary hackers more than is reasonable in humor.
  5. The humor does not have to be computer-related.

GNUer是语言的发明创造专家和幽默大师,copyleft也来自这里,总之,他们喜欢与世界反着干.....

大部分的文章以声明(claim)结尾,其便以放弃(disclaim)结尾,大部分公司都是是将源代码作为最高机密,GNU却提倡开源,于是别人需要保留自己的copyright,GNU copyleft......其实copyleft也是收到保护的-_-!

 

这里从其中选一面贴过来:

from http://www.gnu.org/fun/jokes/declarations.html

 

Funny C/C++ declarations!

auto accident;
register voters;
static electricity;
struct by_lightning;
void *where_prohibited;
char broiled;
short circuit;
short changed;
long johns;
long dong_silver;    /* Submitted by Juan Carlos Castro */
unsigned long letter;
double entendre;
double trouble;
union organizer;
union jack;
float valve;
short pants;
union station;
void check; unsigned check;
struct dumb by[sizeof member];
union onion;	/*submitted by srp*/

/*if GCC extensions are allowed -- Dave Gilbert */
long long ago; /* in a galaxy far far away */

/* Submitted by James Buchanan */

const ipated;
case closed:
double or_nothing;
short sighted;
void if_removed;    /* warranty */
volatile buggy_code;
unsigned anonymous;
int erbreed;    /* duelling banjos */

/* Borland's additional C keywords */:
huge penis;
interrupt ed;
near sighted;
far out;


men()
{
   goto pub;
  pub:
   return pissed;
}

women()
{
   goto bathroom;
  bathroom:
   while (1) ;
}

class dismissed : public annoyance    /* Submitted by Juan Carlos Castro */

The following was submitted by Pietro Gagliardi:

/* All this was done on August 17, 2007 by Pietro Gagliardi
   You are free to use this code in a citation or (if you have the guts)
   in your own program; just please mention me. */

typedef int number;
class microsoft : public corporation, public enemy<(number) 1> {
public:
	microsoft()
	{
		sanity = 200;
		bill_gates = drop_out();
		ceo = bill_gates;
		while (sanity > 2) {
			sleep(2);
			sanity--;
		}
		steve_ballmer = new class doofus;
	}

#define our int
#define SUCCESS 1

	our year_2006_goals()
	{
		delete bill_gates;
		ceo = steve_ballmer;
		sanity -= 200;
		return SUCCESS;
	}
protected:
	int sanity;
	class doofus ceo, bill_gates, steve_ballmer;
};

typedef int iq;
const iq of_steve_ballmer = -4, of_steve_jobs = MENSA_MINIMUM - 1,
         of_linus_torvalds = MENSA_MINIMUM, of_bill_gates = UNDEFINED;

/* Here are some that make use of the preprocessor and the Unix programming interface */
#include <sys/types.h>

#define middle
middle class businessMan {
	ino_t want_to_go_to_work;
#if speeding_to_work_because_you_are_late
	off_t o_jail;
#endif
};

class mate
{
	ino_t wannagotoskool;
};

class woman {
#define be
private:
	be friend class of_girls;
	off_t o_the_mall()
	{
		for (;;)
			mall.go_to(rand()).shop();
	}
};

class clown {
!friend class teacher;
friend class mate;
};

 

 

个人最为欣赏的是这两个函数的定义:

men()
{
   goto pub;
  pub:
   return pissed;
}

women()
{
   goto bathroom;
  bathroom:
   while (1) ;
}

男人就是去酒吧喝醉了回来的动物,女人就是进入浴室再也不出来的动物-_-!

 

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

从Unicode到太玄经


Unicode到太玄经

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

本来仅仅是想找个BMP以外的Unicode字段来验证一下我用Python写的用于UTF-16编码的函数,结果发现在Supplementary Multilingual Plane有这么一条,看起来比较突兀:Tai Xuan Jing Symbols (1D300–1D35F)-_-!进去看一下更加突兀了-_-!

太玄经的符号在Unicode有编码-_-!

作为Unicode学习的附加,顺便还了解了一下太玄经......................

Tai Xuan Jing

From Wikipedia, the free encyclopedia

Jump to: navigation, search

The text Tài Xuán Jīng ("Canon of Supreme Mystery", Chinese: 太玄經) was composed by the Confucian writer Yáng Xióng (Chinese: 揚雄/扬雄; pinyin: Yáng Xióng; Wade-Giles: Yang Hsiung; 53 BCE-18 CE). The first draft of this work was completed in 2BCE (in the decade before the fall of the Western Han Dynasty). This text is also known in the West as The Alternative I Ching and The Elemental Changes.

The Tai Xuan Jing symbols [1] represent a primary level of semantic notation in the text and are an extension of the Yì Jīng symbols. The mono-, di- and tetragrams consist of three monograms:

  • the unbroken line ( ⚊) for heaven (Chinese: ; pinyin: tiān),
  • once broken line ( ⚋) for earth (Chinese: ; pinyin: dì),
  • twice broken line (

阅读全文....

加班到十点,没有时间,弄个输出套接字接收和返回的Buffer大小的程序


加班到十点,没有时间,弄个输出套接字接收和返回的Buffer大小的程序

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

Ubuntu8.04桌面版下,测试的结果为

Socket default Receive Buffer is 87380

Socket default Send Buffer is 16384

与作者在freebsd4.8中的稍有不同,接收缓冲区略大,发送缓冲区略小。

作者得出的结果分别是57344,32768

在我的系统中,接收的缓存实在是够大

 

源代码:

 1 #include    "unp.h"
 2
 3 int main(int argc, char **argv)
 4 {
 5     int    sockfd, n;
 6     /*   struct sockaddr_in    servaddr; */
 7     int liRcvSize = 0;
 8     socklen_t liRcvLen = sizeof(liRcvSize);
 9     int liSndSize = 0;
10     socklen_t liSndLen = sizeof(liSndSize);
11
12     if ((sockfd = Socket(AF_INET, SOCK_STREAM, 0)) < 0)
13     {
14         err_sys("Socket Create failed/n");
15     }
16
17     if ( ( n = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &liRcvSize, &liRcvLen) ) < 0)
18     {
19         err_sys("getsocketopt recv buffer run failed/n");
20     }
21
22     if ( ( n = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &liSndSize, &liSndLen) ) < 0)
23     {
24         err_sys("getsocketopt send buffer run failed/n");
25     }
26
27     close(sockfd);
28
29     printf("Socket default Receive Buffer is %d/n", liRcvSize);
30     printf("Socket default Send Buffer is %d/n", liSndSize);
31
32     
33     exit(0);
34 }

 

 

Thread model: posix

gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

ANSI C程序

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

文件md5计算小工具

呵呵,这是我在公司花了一两个小时做的一个内部用的小工具,最近公司的游戏开放下载了,竟然把这个内部用的小工具放出来下载,给外部人员用来计算游戏的md5值-_-!晕死了,这样连版权,公司名等信息都没有写的东西就这样放出来了。。。。呵呵,因为是自己做的东西,拿过来,留作纪念:)

md5maker.rar

在老地方http://groups.google.com/group/jiutianfile/

阅读全文....

学习网络编程ubuntu桌面版比服务器版更好?

郁闷坏了,在一再确定程序没有问题的前提下,我放弃了原有Ubuntu服务器版的稳定配置(配置了很久啊,当然也许就是那个时候鼓捣的配置,弄得程序跑不成功),昨天重新安了个Ubuntu的桌面版,第一件事就是测以前的程序,一次成功-_-!
再次郁闷一下,然后一次手误,将ssh_config配置文件删了,半天找不回来,网上教学的多,真有完整配置文件的少,将ssh,openssh-server卸载了重新安装,还是没有新的配置文件,。。。。。总算找到配置文件后,又要想办法将原有的X11删掉,呵呵,真是麻烦啊。。。。。不过,好歹,网络程序可以跑了,不要再郁闷的Unix网络编程的书,然后在Windows下跑程序了-_-!

阅读全文....

以此纪念刚开始在linux上学习网络编程的失败-_-!


以此纪念刚开始在linux上学习网络编程的失败-_-!

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

从一开始的学习到现在,我的Ubuntu 8.04服务器版本就从来没有正常的跑过一个服务器程序,亏它还是服务器版本的,郁闷的我要死。目前为止的正常的服务器端网络程序都是在Windows下运行成功的,比如第一次那个daytime服务器,都是靠着移植到windows下才能成功,不过不停的调试啊,调试啊,gdb倒是熟悉了不少,还顺便熟悉了一堆的网络调试工具,linux下的netstat,tcpdumpwindows下的Wiresharklinux因为没有X window,所以用不了)倒是真熟悉了很多,我都真不知道这样的死Ubuntu对于学习是好是坏了,假如没有碰到这么多问题的话,我不会调试一个那样简单的程序那么多次,不会这样的进一步熟悉那些特别简单的套接口API,真是,郁闷了。

中间发帖求救,有人说是防火墙,我配置了半天也没有反应,直接将ufw,iptables什么的都卸载了,结果还是不行!

最新的调试结果就是netstat显示的确服务器端listen成功了, tcpdump可以看到客户端的发送的SYN包,但是就是服务器不回ACK包,郁闷的客户端所以总是不停的发送几次SYN包,然后connect failed了,奇怪的家伙,我今晚准备下个ubuntu的普通版本试一下,服务器版本可能为了安全做了太多的手脚,我配置linux的能力又那么弱-_-!光学些bash,makefile什么的,对于配置文件的修改实在是不行,不然我也不会为了samba的配置郁闷到死,然后干脆传输文件都直接改用WinSCP,通过SSH传输,而不是通过共享了。唉。。。。。还是公司好,有管理员。

ubuntu普通版本还不行,我就只好换回FC了。。。。刚才看了一下已经到10-_-!我上一次用的时候还是FC6呢,那时候45张盘,现在FC10只有1CD了,最近的操作系统瘦身工程进行的还挺彻底。要知道,连最最老的经典的RH9那时候都是4张盘。

呵呵,其实想起来,看的其实是UNIX的书,弄个真正的UNIX,比如FreeBSD什么的应该也挺不错的,可惜最近工作那个忙的啊。。。。都快吐血了,游戏快要上大规模的内测了,老总,总监催进度催的我一天头是大的,刚开始弄游戏的主逻辑服务器,第二天就要我设计并添加模块-_-!实在是@#%#$^@#$^$%@&$%基本上就那句话,不能上硬着头皮眯着眼睛也要上!唉。。。。所以嘛,还是暂时收收心吧。。。好好把网络编程学好都不错了,连Linux都没有弄转,呵呵,还是老实点好。

 

以下是我痛苦的调试经历:-_-!

@ubuntu:~$ netstat -a

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State

tcp        0      0 *:13000                 *:*                     LISTEN

 

 

@ubuntu:~$ netstat -a

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State

tcp        0      0 *:daytime               *:*                     LISTEN

 

@ubuntu:~$ netstat -a

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State

tcp        0      0 *:9877                  *:*                     LISTEN

 

三个不同的程序,都是卡在listen上。。。。

@ubuntu:~/test/testclient$ ./test 127.0.0.1

connet failed.

@ubuntu:~/test/testclient$ ./test 127.0.0.1

connet failed.

 

可怜的客户端啊。。。一次一次的connet failed

其实它实在不停的尝试的。。。。

一次:

@ubuntu:~$ sudo tcpdump port 9877

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

22:04:03.173472 IP 192.168.0.158.46269 > localhost.9877: S 1088742785:1088742785(0) win 5840 <mss 1460,sackOK,timestamp 95154 0,nop,wscale 4>

22:04:06.171580 IP 192.168.0.158.46269 > localhost.9877: S 1088742785:1088742785(0) win 5840 <mss 1460,sackOK,timestamp 95904 0,nop,wscale 4>

 

两次:

@ubuntu:~$ sudo tcpdump port 9877 -vv

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

22:05:09.022315 IP (tos 0x0, ttl 64, id 16507, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0xef4b (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 111616 0,nop,wscale 4>

22:05:12.019572 IP (tos 0x0, ttl 64, id 16508, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0xec5d (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 112366 0,nop,wscale 4>

22:05:18.019572 IP (tos 0x0, ttl 64, id 16509, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0xe681 (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 113866 0,nop,wscale 4>

22:05:30.019593 IP (tos 0x0, ttl 64, id 16510, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0xdac9 (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 116866 0,nop,wscale 4>

22:05:54.019575 IP (tos 0x0, ttl 64, id 16511, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0xc359 (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 122866 0,nop,wscale 4>

22:06:42.019581 IP (tos 0x0, ttl 64, id 16512, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.46270 > localhost.9877: S, cksum 0x9479 (correct), 2110715003:2110715003(0) win 5840 <mss 1460,sackOK,timestamp 134866 0,nop,wscale 4>

 

6 packets captured

6 packets received by filter

0 packets dropped by kernel

 

三次:

@ubuntu:~$ sudo tcpdump port 13000 -vv

[sudo] password for xqh:

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

22:44:49.480945 IP (tos 0x0, ttl 64, id 10118, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0xebc4 (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 706731 0,nop,wscale 4>

22:44:52.479579 IP (tos 0x0, ttl 64, id 10119, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0xe8d6 (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 707481 0,nop,wscale 4>

22:44:58.479574 IP (tos 0x0, ttl 64, id 10120, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0xe2fa (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 708981 0,nop,wscale 4>

22:45:10.479576 IP (tos 0x0, ttl 64, id 10121, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0xd742 (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 711981 0,nop,wscale 4>

22:45:34.479596 IP (tos 0x0, ttl 64, id 10122, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0xbfd2 (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 717981 0,nop,wscale 4>

22:46:22.479584 IP (tos 0x0, ttl 64, id 10123, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.60205 > localhost.13000: S, cksum 0x90f2 (correct), 793636653:793636653(0) win 5840 <mss 1460,sackOK,timestamp 729981 0,nop,wscale 4>

22:49:22.209124 IP (tos 0x0, ttl 64, id 2573, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0x20c8 (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 774913 0,nop,wscale 4>

22:49:25.207577 IP (tos 0x0, ttl 64, id 2574, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0x1dda (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 775663 0,nop,wscale 4>

22:49:31.207570 IP (tos 0x0, ttl 64, id 2575, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0x17fe (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 777163 0,nop,wscale 4>

22:49:43.207579 IP (tos 0x0, ttl 64, id 2576, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0x0c46 (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 780163 0,nop,wscale 4>

22:50:07.207588 IP (tos 0x0, ttl 64, id 2577, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0xf4d5 (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 786163 0,nop,wscale 4>

22:50:55.207580 IP (tos 0x0, ttl 64, id 2578, offset 0, flags [DF], proto TCP (6), length 60) 192.168.0.158.49879 > localhost.13000: S, cksum 0xc5f5 (correct), 778754316:778754316(0) win 5840 <mss 1460,sackOK,timestamp 798163 0,nop,wscale 4>

 

记住,就算我不改一个字,原《UNIX Network Programming》第一卷第三版一书的源程序(我试过45个前面几章的例子了),都是可以编译,可以运行,但是状况都是同样的。。。那就是connect不会成功。-_-!

处于对于原程序的一丝不信任,我自己重写了一些程序,但是几乎同样的程序,在Windows下相当的正常,但是在Ubuntu 8.04服务器版本上,还是同样的状况!!有没有人可以给我个解释啊。。。。。朝闻道夕死可矣。。。。。

 

举个例子,比如,linux下的两个程序:

服务器端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/socket.h>
 4 #include <sys/time.h>
 5 #include <time.h>
 6 #include <netinet/in.h>
 7 #include <errno.h>
 8 #include <string.h>
 9 #include <unistd.h>
10
11
12 #define MAXLINE 1000
13 int main(int argc, char* argv[])
14 {
15     int    listenfd, connfd;
16     struct sockaddr_in servaddr;
17     //char buff[MAXLINE] = {0};
18     //time_t   ticks;
19
20     listenfd = socket(AF_INET, SOCK_STREAM, 0);
21     if(0 == listenfd)
22     {
23         printf("socket Error./n");
24         return -1;
25     }
26
27     memset(&servaddr, 0, sizeof(servaddr));
28     servaddr.sin_family      = AF_INET;
29     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
30     servaddr.sin_port        = htons(13000);   /* daytime server */
31
32     if( 0 != bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)))
33     {
34         printf("bind error./n");
35         close(listenfd);
36         return -1;
37     }
38
39     if( 0 != listen(listenfd, 10))
40     {
41         printf("listen error./n");
42         close(listenfd);
43         return -1;
44     }
45
46     printf("listen right./n");
47
48     char buffRecv[MAXLINE] = {0};
49     connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
50         
51     printf("have accept./n");
52
53     while(true)
54     {
55         int n = 0;
56         if( 0 == (n = read(connfd, buffRecv, MAXLINE)) )
57         {
58             printf("recv failed/n");
59             break;
60         }
61         buffRecv[n] = 0;
62         if( 0 == (n = write(connfd, buffRecv, strlen(buffRecv))) )
63         {
64             printf("send failed./n");
65             break;
66         }
67         fputs(buffRecv, stdout);
68     }
69     close(connfd);
70     exit(0);
71 }
72

 

客户端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/socket.h>
 4 #include <sys/time.h>
 5 #include <time.h>
 6 #include <netinet/in.h>
 7 #include <errno.h>
 8 #include <string.h>
 9 #include <unistd.h>
10 #include <arpa/inet.h>
11
12 #define MAXLINE 1000
13
14 void str_cli(FILE *fp, int sockfd)
15 {
16     char sendline[MAXLINE] = {0};
17     char recvline[MAXLINE] = {0};
18     while ( (fgets(sendline, MAXLINE, fp)) != NULL)
19     {
20
21         if(0 == send(sockfd, sendline, strlen(sendline), 0))
22         {
23             printf("send failed./n");
24             break ;
25         }
26     }
27     close(sockfd);
28 }
29
30 int main(int argc, char* argv[])
31 {
32     if (argc != 2)
33     {
34         printf("usage: tcpcli <IPaddress>");
35         exit(1);
36     }
37
38     int    sockfd = 0;
39     sockfd = socket(AF_INET, SOCK_STREAM, 0);
40
41     struct sockaddr_in servaddr;
42     memset(&servaddr, 0, sizeof(servaddr));
43     servaddr.sin_family      = AF_INET;
44     servaddr.sin_addr.s_addr = inet_addr(argv[1]);
45     servaddr.sin_port        = htons(13000);   /* daytime server */
46
47     if( 0 != connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
48     {
49         printf("connet failed./n");
50         close(sockfd);
51         return -1;
52     }
53
54     str_cli(stdin, sockfd);        /* do it all */
55     exit(0);
56 }
57

 

 

就这么简单的程序,硬是成功不了,何解?

几乎同样的程序,比如:

服务器端:

#include "Winsock2.h"

//#include "python.h"

 

//void CallPython(const char* apszPy)

//{

//  Py_Initialize();

//

//  PyRun_SimpleString(apszPy);

//

//  Py_Finalize();

//}

#define MAXLINE 1000

int main(int argc, char **argv)

{

    WORD wVersionRequested;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 2, 2 );

 

    // windows下此初始化为必须

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

       return -1;

    }

 

    SOCKET listenfd, connfd;

    struct sockaddr_in   servaddr;

    char   buff[MAXLINE];

    time_t ticks;

 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    if(INVALID_SOCKET == listenfd)

    {

       printf("socket Error: %d",WSAGetLastError());

       return -1;

    }

 

    ZeroMemory(&servaddr, sizeof(servaddr));

    servaddr.sin_family      = AF_INET;

    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    servaddr.sin_port        = htons(13);  /* daytime server */

 

    bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

 

    listen(listenfd, SOMAXCONN);

 

    char   buffRecv[MAXLINE] = {0};

      

    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);

      

    while(true)

    {

       int n = 0;

       if( 0 == (n = recv(connfd, buffRecv, MAXLINE,0)) )

       {

           printf("recv failed, Error Code: %d", WSAGetLastError());

           break;

       }

       buffRecv[n] = 0;

//     CallPython(buffRecv);

       if( 0 == (n = send(connfd, buffRecv, strlen(buffRecv),0)) )

       {

           printf("send failed, Error Code: %d", WSAGetLastError());

           break;

 

       }

 

       fputs(buffRecv, stdout);

    }

 

    closesocket(connfd);

}

 

 

 

客户端:

#include "Winsock2.h"

#include "errno.h"

#include "stdlib.h"

 

#define MAXLINE 1000

void str_cli(FILE *fp, SOCKET sockfd)

{

    char sendline[MAXLINE] = {0};

    char recvline[MAXLINE] = {0};

    while ( (fgets(sendline, MAXLINE, fp)) != NULL)

    {

 

       if(SOCKET_ERROR == send(sockfd, sendline, strlen(sendline), 0))

       {

           printf("send failed, Error Code: %d", WSAGetLastError());

           break ;

       }

    }

    closesocket(sockfd);

}

int main(int argc, char **argv)

{

    WORD wVersionRequested = 0;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 2, 2 );

 

    // windows下此初始化为必须,实际包含加载WinsockDLL的过程

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

       return -1;

    }

    SOCKET               sockfd;

    struct sockaddr_in   servaddr;

 

    if (argc != 2)

    {

       printf("usage: tcpcli <IPaddress>");

       exit(1);

    }

 

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

 

    ZeroMemory(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(13);

    servaddr.sin_addr.s_addr = inet_addr(argv[1]);

 

    if( SOCKET_ERROR == connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)))

    {

       printf("connet failed, Error Code: %d", WSAGetLastError());

       closesocket(sockfd);

       return -1;

    }

 

    str_cli(stdin, sockfd);      /* do it all */

 

    system("pause");

    exit(0);

}

 

 

就是运行的那么正常-_-!给我个解释?。。。。。另外,虽然做了写了好几个服务器了,我最近才知道。。原来。。。recv,send本来就是标准的套接口API。。。。我一直以为这些都是windows扩展的-_-!Unix Network Programming》书以前只看了前面一点,因为前面用的都是read,write接口来写套接字,所以嘛。。。呵呵,误解了,以前还常喊windows下用的recv,send很奇怪呢-_-!太无知了,所以嘛,还是要好好学习底层知识才行。。。不能太依赖于公司的网络框架了,虽然那个框架写的真是不赖。。。好用的很。。。

有在Ubuntu 8.04版本上成功accept的兄弟,请告知怎么样配置的。。。。

 

以此纪念刚开始在linux上学习网络编程的失败-_-!

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

为C++的map翻案,map实际是排序并且迭代效率不低的


C++的map翻案,map实际是排序并且迭代效率不低的

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

人类都有对未知事物的恐惧,map的使用即是其一,因为RB-Tree实在是太过于复杂,相当的复杂,去实现一个就知道我在说什么了,所以,作为一个C++程序员天生的从C继承过来的那种不知道怎么实现的,就不敢用的天性,很多人不敢好好的使用map,因为,我们不知道它是怎么实现的。我这里不是要来讨论其实现,请参考数据结构相关书籍,我这里仅仅是从外部测试来证实其特性,这样花费的功夫是最少的。

首先是map的排序性,因为hash表的混淆,导致很多人认为map不是排序的,实际中我看我们总监都不能肯定这件事情,所以常常仅仅将map作为一个搜索结构,然后另外弄一个list去处理排序并迭代的事情,这样相当于将一个map可以做的事情拆开来做,并且每次增删操作都要同步处理两件事情-_-!

其次是其迭代的速度,因为map的插入速度接近O(logN),删除速度接近O(logN),搜索速度也接近O(logN),所以出于好事不能让其占尽的原则,map总有个缺点吧,迭代速度就是其一,至于慢到什么地步,到了迭代100个元素需要10毫秒的地步?测试数据面前说话。以下测试程序就是见证了这个问题,写这个测试程序,来源于工作中我希望利用map的排序性和multimap的可重复键特性来简化工作,但是开会讨论的结果是因为大家对map,multimap不熟悉而不能确定,以下是确定的过程:

(单位,毫秒,结果来自aqtime5,机器酷睿E2140,需要提醒的是因为用了aqtimelines处理特性,所以速度会有一定的降低,这里并不是要测试绝对速度,仅仅是与list做比较,假如有人说list的迭代都慢的不能接受,那么map的迭代自然也不能接受)

#include "stdafx.h"

#include <list>

#include <map>

#include <iostream>

#include <iterator>

#include <algorithm>

#include <functional>

using namespace std;

 

 

 

// Hit Count          : 1

// Time               : 0.00

// Time with Children : 0.01

multimap<int, int, greater<int>> goMMap;

// Hit Count          : 1

// Time               : 0.00

// Time with Children : 0.00

map<int, int, greater<int>> goMap;

// Hit Count          : 1

// Time               : 0.00

// Time with Children : 0.01

list<int> goList;

 

// 测试一,Map的排序,实际是搜索二叉树的前序遍历

// 实际上搜索二叉树本来就是排好序的,只是说到map比较容易和hashmap混淆

// hash表是不排序的,博客上有个哈希表的实现,可以看到,就是通过哈希算法

// 找到一个独特的位置,然后尽快搜索的过程

void TestMapOrder()

// Hit Count          : 1

// Time               : 0.20

// Time with Children : 35.69

{

 

    // 有序的插入对于平衡搜索二叉树来说是效率最慢的一种

    for(int i=0; i < 100; ++i)

    {

       goMap.insert(make_pair(i, 1));

    }

 

    for(map<int, int,  greater<int>>::const_iterator lit = goMap.begin();

       lit != goMap.end(); ++lit)

    {

       cout <<lit->first << " ";

    }

 

    cout <<endl;

    // 有序的插入对于平衡搜索二叉树来说是效率最慢的一种

    for(int i=0; i < 100; ++i)

    {

       goMMap.insert(make_pair(i-1, 1));

       goMMap.insert(make_pair(i, 1));

       goMMap.insert(make_pair(i+1, 1));

    }

 

    for(multimap<int, int, greater<int>>::const_iterator lit = goMMap.begin();

       lit != goMMap.end(); ++lit)

    {

       cout <<lit->first << " ";

    }

 

    cout <<endl;

}

 

#define TEST_TIMES 100

void MapIterate()

// Hit Count          : 1

// Time               : 2.31

// Time with Children : 2.59

{

    int j = 0;

    for(int i=0; i < TEST_TIMES; ++i)

    {

       for(multimap<int, int, greater<int>>::const_iterator lit = goMMap.begin();

           lit != goMMap.end(); ++lit)

       {

           j+=lit->first;

       }

 

    }

    cout <<j <<endl;

}

 

void ListIterate()

// Hit Count          : 1

// Time               : 1.95

// Time with Children : 2.26

{

    int j = 0;

    for(int i=0; i < TEST_TIMES; ++i)

    {

       for(list<int>::const_iterator lit = goList.begin();

           lit != goList.end(); ++lit)

       {

           j+=*lit;

       }

 

    }

    cout <<j <<endl;

}

 

// 主要是前序遍历迭代时的速度,虽然插入,删除,搜索速度都快才是map的强项

// 但是实际使用中不能忍受太慢的迭代速度,这里和list做比较

void TestMapSpeed()

// Hit Count          : 1

// Time               : 0.02

// Time with Children : 5.01

{

    for(int i=0; i < 100; ++i)

    {

       goList.push_back(i-1);

       goList.push_back(i);

       goList.push_back(i+1);

    }

 

    MapIterate();

    ListIterate();

}

 

int _tmain(int argc, _TCHAR* argv[])

// Hit Count          : 1

// Time               : 0.00

// Time with Children : 40.71

{

 

    TestMapOrder();

    TestMapSpeed();

 

    return 0;

}

 

速度在上面已经有输出了,300元素,迭代100次,list花费2.26秒,multimap花费2.59秒,multimap的迭代速度的确比list慢,但是慢的比率实在是不太多,没有到传言中不可接受的地步,下面会做一个加强版的测试,测试在元素非常多(2万)的情况下,multimap的迭代速度降低的影响。

以上程序输出:

99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73

 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 4

6 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20

19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

 

100 99 99 98 98 98 97 97 97 96 96 96 95 95 95 94 94 94 93 93 93 92 92 92 91 91 9

1 90 90 90 89 89 89 88 88 88 87 87 87 86 86 86 85 85 85 84 84 84 83 83 83 82 82

82 81 81 81 80 80 80 79 79 79 78 78 78 77 77 77 76 76 76 75 75 75 74 74 74 73 73

 73 72 72 72 71 71 71 70 70 70 69 69 69 68 68 68 67 67 67 66 66 66 65 65 65 64 6

4 64 63 63 63 62 62 62 61 61 61 60 60 60 59 59 59 58 58 58 57 57 57 56 56 56 55

55 55 54 54 54 53 53 53 52 52 52 51 51 51 50 50 50 49 49 49 48 48 48 47 47 47 46

 46 46 45 45 45 44 44 44 43 43 43 42 42 42 41 41 41 40 40 40 39 39 39 38 38 38 3

7 37 37 36 36 36 35 35 35 34 34 34 33 33 33 32 32 32 31 31 31 30 30 30 29 29 29

28 28 28 27 27 27 26 26 26 25 25 25 24 24 24 23 23 23 22 22 22 21 21 21 20 20 20

 19 19 19 18 18 18 17 17 17 16 16 16 15 15 15 14 14 14 13 13 13 12 12 12 11 11 1

1 10 10 10 9 9 9 8 8 8 7 7 7 6 6 6 5 5 5 4 4 4 3 3 3 2 2 2 1 1 1 0 0 -1

1485000

1485000

 

有点乱,从前面几排可以看出map是排序的,迭代可以按顺序输出。

后面的也证实,multimap也是同样。

最后的两排证明list,multmap的确经过了同样的迭代。

 

另外,经过一些反汇编分析的学习后,我不再完全相信VS了,因为其在release版本下有可能进行不可思议的省略优化,比如这里,最后的程序最后可能仅仅是直接保存了1485000并进行输出-_-!呵呵,那也不可能需要2毫秒。。。。看了反汇编代码确定,的确map,list都有完整的迭代过程。

 

其实从实现上考虑,可以想到,随着元素的增加,list的迭代速度是不会变慢的,但是map作为二叉树,树越大,其遍历的速度会越来越慢,这里为了看看到底会有多慢,将元素的个数扩大到一个实际中有可能会碰到的数值,3万,再来测试迭代速度。

Routine Name     Time      Time with Children    Shared Time Hit Count

MapIterate   1.15       1.57       73.18     1

ListIterate     0.25       0.51       49.40     1

#define TEST_TIMES 100

void MapIterate()

// Hit Count          : 1

// Time               : 1.15

// Time with Children : 1.57

{

    int j = 0;

    for(multimap<int, int, greater<int>>::const_iterator lit = goMMap.begin();

       lit != goMMap.end(); ++lit)

    {

       j+=lit->first;

    }

    cout <<j <<endl;

}

 

void ListIterate()

// Hit Count          : 1

// Time               : 0.25

// Time with Children : 0.51

{

    int j = 0;

    for(list<int>::const_iterator lit = goList.begin();

       lit != goList.end(); ++lit)

    {

       j+=*lit;

    }

    cout <<j <<endl;

}

 

3万应该是我们公司游戏中我做的专卖店模块可能碰到的最大值了,这里map的迭代已经比list慢了3倍了,的确是慢的太多,看来这个世界上流言也不是无缘无故的有的,还是略有其事。至于慢3倍的迭代能不能接受,这个就可能得考虑一下了。不用multimap用什么呢?

用一个map来做搜索,然后再维护一个list用来遍历?维护两个容器的复杂度自然要比维护一个容器的复杂度高的多-_-!而且速度快很多吗?需要接受的是添加,删除时候的速度要慢一倍以上,也许还要远大于1倍,问题出在list到底排不排序?不排序,那删除的时候估计够呛,排序?那添加的时候呢?呵呵,map的优势不在于增加元素快,再快也没有list,vectorpush_back快,不在于删除元素块,再快也没有list,vectorpop_back快,也不在于搜索速度快,再快也没有排序后的vectorlistfind快,从上面看来,map的迭代还是非常慢的,但是map为什么好用呢?甚至成为了构建python,lua等脚本语言中的结构。就在于其所有操作的平均的效率,都不差。

这点就像很多人批评C++一样,高不成低不就,但是还是有人使用C++,就在于同样的特性在使用的时候也可以是比C语言的抽象能力更强,比其他高级语言的速度更快,更接近底层。

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

其实个人感觉,真正可能会使C++成为历史的是将底层和上层完全分开的潮流,那样才会架空C++的空间。比如,底层与硬件打交道和要求速度非常快的部分交给C,然后上层逻辑全部交给Python等脚本语言,这才是C++最怕的事情。事实上使用过一些如python,mysql,luaAPI后就会发现,不仅仅是windows API,事实上世界上大部分应用程序在提供自己的扩展接口时,基本都是C接口,毕竟因为C++的特性,要提供一个兼容的类接口不是那么容易的,这就是世界的格局,C语言几乎不可能从软件世界消失,因为它是如英语一样的世界通用语言,虽然C++的社团不断的希望融入这个世界,mysql也有第3方封装的C++ 接口,lua也有众多C++绑定接口,boost.python库的出现就是更是使C++Python写扩展更加容易,但是要为世界所接受,仍然任重而道远。

很多人将python,lua等脚本语言称为胶水语言,我个人希望C++将来可以成为连接上层与下层的桥梁语言,可惜的是,这一点的实现已经越来越远,唯一的希望寄托在C++09x标准上了。

 

阅读全文....

潜心开始学习网络编程的第一步 ,UNP(Unix Network Programming)第一章,时间服务器到windows的移植


潜心开始学习网络编程的第一步 UNP(Unix Network Programming)第一章,时间服务器到windows的移植

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

 

学的如此之杂,绝不是我的初衷,但是事实已经形成了,还是按照刚工作时的计划,好好的学习网络技术吧。虽说我已远不是以前服务器组的成员了。。。虽说我其实开发了好几个服务器了,但是那是在公司的框架之上的,连套接字使用的机会都及其之少。。。实在谈不上什么网络编程的经验,那种开发基本上做好的包的映射和MFC的消息机制区别都不大了。

今天是调整心态并转换方向的第一天,本来以为没有什么好说的-_-!但是却给我碰到意外了。

UNPv1中最前面的时间客户端/服务器程序在我的Ubuntu中跑的没有效果-_-!

而且调试的时候都是直接分别在connectaccept上阻塞了,估计是网络可能没有调好,郁闷死了。

于是我将其中的时间服务器程序移植到Windows下了-_-!基本上相当于搬....

更改后源代码如下:

#include <time.h>

#include "Winsock2.h"

 

#define MAXLINE 1000

int

main(int argc, char **argv)

{

    WORD wVersionRequested;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 2, 2 );

 

    // windows下此初始化为必须

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

       return -1;

    }

 

    SOCKET listenfd, connfd;

    struct sockaddr_in   servaddr;

    char   buff[MAXLINE];

    time_t ticks;

 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    if(INVALID_SOCKET == listenfd)

    {

       printf("socket Error: %d",WSAGetLastError());

       return -1;

    }

 

    ZeroMemory(&servaddr, sizeof(servaddr));

    servaddr.sin_family      = AF_INET;

    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    servaddr.sin_port        = htons(13);  /* daytime server */

 

    bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

 

    listen(listenfd, SOMAXCONN);

 

    for ( ; ; ) {

       connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);

 

       ticks = time(NULL);

       _snprintf(buff, sizeof(buff), "%.24s/r", ctime(&ticks));

 

       // 相当诡异的write换成了send

       send(connfd, buff, strlen(buff),MSG_OOB);

 

       closesocket(connfd);

    }

}

 

然后通过Ubuntu上跑的客户端来连接这台windows上的服务器就好了-_-!莫名其妙。。。。。。可能还是属于我Linux下的配置和管理不太熟悉吧。。。但是运行服务器后,netstat却的确也没有看到服务器有监听端口啊。。。程序又没有问题....无奈了。

 

对于windows下的套接口使用源程序,有几点想说一下,因为我进入公司当时分配在服务器组,学的第一课是序列化,第二课就是网络基础啦,当时看的也是这本Stevens的经典著作。。。呵呵,都是将Unix环境的,所以当时在公司调试自己的Windows程序,光是因为没有使用WSAStartup初始化就卡了我大半天-_-!

的确是很诡异的用法,MS自己突发奇想加上的东西,我当时看的是UNP。。怎么会知道呢。。。。。那时候光是htonl, htons这种函数需要调用都不知道。。。。也不知道为什么要调用。。。。光是蒙着头乱蒙-_-!还好,现在还懂点皮毛了。呵呵

另外,原有的包装函数我都是直接用原始的函数替换了,也没有加错误判断,不是什么好习惯。仅作学习使用。

 

 

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

通过全局变量和自擦除代码来防Dump(2)


通过全局变量和自擦除代码来防Dump(2)

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

通过全局变量和自擦除代码来防Dump 》中我提到了用WriteProcessMemory来完成代码段的自擦除,其实这并不是什么好的手段,因为使用了Win32 API,对于分析你代码的人来说,这是明摆着告诉对方你要干什么,破解手段在原文中也提到了不少。其实,当时我去搜寻WriteMemroy API但是并不存在的时候,我就在想,为什么微软不提供,并且,同样的,有ReadProcessMemory但是有ReadMemory,为什么要使用的时候都需要通过GetCurrentProcess()作为第一参数这样奇怪的形式,这个MS一贯的作风不符。这两个函数只在WinCE中有提供,普通Windows并没有,其实后来仔细想想就想通了,因为读写另外的进程的内存你必须要通过额外API,所以有这样的API给你来使用,但是读写自己的内存根本就不需要别的特殊的API,自己进程访问和改写自己进程中的数据是没有限制的。因此,需要做自擦除的操作仅仅需要memcpy或者memset就可以了!

下面是改进的示例:

 1 #include "windows.h"
 2 #include "tchar.h"
 3
 4 void Run()
 5 {
 6     // begin of the func
 7     DWORD ldwBegin = 0;
 8     __asm
 9     {
10         call $+5
11         pop eax
12         mov ldwBegin, eax
13     }
14     DWORD ldwOldPro = 0;
15     // Must have this step
16     if(!VirtualProtect((void*)ldwBegin, 1000, PAGE_EXECUTE_READWRITE, &ldwOldPro))
17     {
18         printf( "VirtualProtectEx failed (%d)./n", GetLastError() );
19         return;
20     }
21
22     MessageBox(NULL, _T("Right"), _T("Hello World"), MB_OK);
23
24         // begin of the func
25     DWORD ldwEnd = 0;
26     __asm
27     {
28         call $+5
29         pop eax
30         mov ldwEnd, eax
31     }
32
33     DWORD ldwFuncLen = ldwEnd - ldwBegin;
34     BYTE *lpbyRand = new BYTE[ldwFuncLen];
35
36     DWORD ldwWritten = 0;
37     memcpy((void*)ldwBegin, lpbyRand, ldwFuncLen);
38
39     delete[] lpbyRand;
40 }
41
42 int main(int argc, char* argv[])
43 {
44     Run();
45     MessageBox(NULL, _T("OK"), _T("OK"), MB_OK);
46
47     return 0;
48 }
49
50

 

这样做后,就没有办法简单的将memcpy挂上使其无效化来使得擦除无效,而且,从发现你的目的的难度上来讲也更加大一些,毕竟memcpy这种函数使用的频率太高了,你可能因为各种原因使用它,而不仅仅是反Dump的目的。这也加大了分析的难度:)

 

 

 

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

通过全局变量和自擦除代码来防Dump


通过全局变量和自擦除代码来防Dump

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

一般而言,你的程序一旦运行起来就没有办法防止Dump了,因为所有的数据都在内存中了,而且,为了更好的Dump完整程序,程序将要启动,还未启动时的Dump,任你程序中有多少防Dump的方法都没有用。这里只能结合两种方式来实现反Dump,其一,程序运行的时候其本身数据并不是完整的,以前我已经讲过方法了, EXE文件不能直接启动的方法以防止直接调试的方法》,只要多用几次这样的方法,比如启动代码无效,中间某段代码也无效,然后通过与启动程序的交互来完成中间代码的修改,只在启动程序通知后才继续运行,以防止错误。这样就没有办法通过在文中介绍的启动时DumpDump数据了。对于Dump的作用还不理解的,可以去使用一下LordPEDump功能,保证你能够见识到工具的作用性如此之大,并认识到自己程序多么的脆弱。

通过全局变量防Dump

但是这种方法有个缺陷是,程序一旦运行起来,所有代码段的数据都是正确的了,还是可以Dump出来,有种方式是用某个全局变量来指示是否是Dump出来的数据或者是正常运行的数据。

这里介绍一下:

 1
 2 #include "stdafx.h"
 3 #include "windows.h"
 4 #include "tchar.h"
 5
 6 bool gbDumped = false;
 7
 8 int main(int argc, char* argv[])
 9 {
10     if(!gbDumped)
11     {
12         gbDumped = true;
13         MessageBox(NULL, _T("Right"), _T("Hello World"), MB_OK);
14     }
15     else
16     {
17         MessageBox(NULL, _T("Dumped me?!"), _T("Find you Dumped me!!"), MB_OK);
18     }
19     return 0;
20 }
21

 

这样只要实在你弹出了对话框后Dump出来的程序其实就是不对的程序,虽然逻辑上将,应该会弹出另外一个对话框,但是实际上对于这样正常流程根本不会走到的地方甚至有可能被编译器所优化,然后导致Dump出来的程序直接崩溃但是这样的程序可以被跟踪调试,通过找到全局变量并修改实在不是什么很难的问题。

下面再将一个稍微复杂一点的办法,让代码一旦运行起来,程序代码段就被破坏,那么这样运行时的Dump也就更加无效了,并且此种方法还可以防止调试。因为完整的程序已经不存在了。

通过自擦除代码来防Dump

原理上也很简单,对于那些只会运行一次的代码,直接在运行后将自己在代码段的内容擦除,可以写入任意值来迷惑调试者,效果更佳。

源代码:

 1 #include "windows.h"
 2 #include "tchar.h"
 3
 4 void Run()
 5 {
 6     // begin of the func
 7     DWORD ldwBegin = 0;
 8     __asm
 9     {
10         call $+5
11         pop eax
12         mov ldwBegin, eax
13     }
14     DWORD ldwOldPro = 0;
15     // Must have this step
16     if(!VirtualProtect((void*)0x401000, 1000, PAGE_EXECUTE_READWRITE, &ldwOldPro))
17     {
18         printf( "VirtualProtectEx failed (%d)./n", GetLastError() );
19         return;
20     }
21
22     MessageBox(NULL, _T("Right"), _T("Hello World"), MB_OK);
23
24         // begin of the func
25     DWORD ldwEnd = 0;
26     __asm
27     {
28         call $+5
29         pop eax
30         mov ldwEnd, eax
31     }
32
33     DWORD ldwFuncLen = ldwEnd - ldwBegin;
34     BYTE *lpbyRand = new BYTE[ldwFuncLen];
35
36     DWORD ldwWritten = 0;
37     if(!WriteProcessMemory(GetCurrentProcess(), (void*)ldwBegin, lpbyRand, ldwFuncLen, &ldwWritten))
38     {
39         printf( "WriteProcessMemory failed (%d)./n", GetLastError() );
40     }
41     delete[] lpbyRand;
42 }
43
44 int main(int argc, char* argv[])
45 {
46     Run();
47     MessageBox(NULL, _T("OK"), _T("OK"), MB_OK);
48
49     return 0;
50 }

 

以上代码,在弹出OK后再Dump,下次再进入Run函数会直接报错,因为后来添进去的其实是堆上的随机数值。

这里需要说明的是

call $+5
pop eax

两句内嵌代码的含义是获取当前的EIP,这在壳中用的非常多,我在这里套用了一下。这样ldwBegin就是Run函数的开始EIP,ldwEnd虽然不是函数结束的EIP,但是主体部分已经包括在内了, 达到这样的效果就足够了。

通过上面的两种方式基本上可以预防住运行时的一次性Dump,而且可以将上述方式扩展,将多段擦除,结合以前讲的方式,将多段代码由启动程序来写入,这样无论是启动时的Dump,还是运行时的Dump都不能获取到正确的内容了。

但是破解方式还是有的,比如这种方式,只需要跟踪调试程序,绕过WriteProcessMemroy函数的调用就可以了,或者直接一点,直接将此API函数挂接上并使其无效,无论多少此的自擦除都会无效。

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....