什么叫达尔文奖?

什么叫达尔文奖?,第1张

达尔文奖(Darwin Awards)由31岁的斯坦福大学教授温蒂·诺斯喀特于1994年创建,此命名是为了表示对生物学家查尔斯·达尔文的敬意,是网络幽默的表现,本荣耀是颁发给身为智人的一分子借着特别愚蠢的方法,使他们被排除在生命的长河之外,并为增进全人类基因库而作出贡献的人士,这些男女不分国籍,更不分老幼。使自己丧失繁殖能力的过程越愚蠢,有越高的机会得到这个荣耀,从而自基因库移除一组不合适的基因。

虽然大部分的获奖者是在身后得到这个荣耀,但只要将他自己移出基因库即可获得资格。在一些情况下该人失去生殖能力亦可以获奖。

一个得奖者必须表现得超出常理的白痴行为,如抛耍手榴弹(克罗地亚,1987年)、为了拍高空急降不穿降落伞就跳出机外(北卡罗来纳,1987年)、或用打火机照亮燃料槽来确定无可燃挥发气体(圣保罗,2002年)。

"荣誉提名"是对于那些未能尽全功移出基因库的人士,因这不是他们的过失。他们愚蠢且危险的举动已足以获得提名,若在他们的下一次尝试,这足以让他人保持与他们的距离。

虽然一些广为人知的达尔文奖获得者已被证实是虚构的,如JATO 火箭车,但使用资料中大部分的获奖者都有由其来源资料证实。

达尔文奖是为“通过愚蠢的方式毁灭了自我,为人类进化(达尔文理论)做出深远贡献”的人颁发的奖项。

“达尔文奖”最初的传播形式是连锁电子邮件。一个具有敏锐的新闻头脑的人,把自己在生活中看到的一个搞笑事件创作成一则轶闻奇事,再把故事发送给朋友分享。朋友再传给朋友的朋友,“达尔文奖”的故事就这样诞生了。这种原始的邮件传递方式源远流长,时至今日仍然广为流传。

1994年在斯坦福大学的网络服务器上,“达尔文奖”的档案正式创建并迅速走红。在世界各地的教室和校园酒吧里,“达尔文奖”都是个热门话题。后来,大家纷纷提出鼓励,要求“达尔文奖”建立起属于自己的网站。

这是一篇妙趣横生的小品文。作者采用生动活泼的笔法,把蝈蝈写得活灵活现,具有很强的可读性。这也是法布尔《昆虫记》整部书的特色。鲁迅曾把《昆虫记》称为“讲昆虫故事”“讲昆虫生活”的楷模。周作人说:“比看那些无聊的小说戏剧更有趣味,更有意义。”的确如此,法布尔笔下的蝈蝈是鲜活的,字里行间洋溢着作者本人对生命的尊重与热爱。

先让学生认真地把课文读一遍,画出生字词。然后读第二遍,画出自己认为最精彩的段落或句子。这样做的目的是让学生切实地感受课文内容。

作者用什么方法引出蝈蝈呢?第1段并没有写蝈蝈,是写在别人欢度国庆的日子里,自己还没有忘记去观察昆虫。“我独自一人”说明作者对他所热爱的事业是多么执著!搞科学研究需要这样的精神。第2段写蝉在夜晚不再鸣叫,它要休息了。突然,蝉的一声哀号引出了本文的“主人公”——蝈蝈。这是多么富有匠心的写作思路!

从第3段开始介绍蝈蝈。作者采用拟人的手法来写蝈蝈。先写它的歌声。蝈蝈的声音是“窃窃自语”,“像是滑轮的响声”,“又像是干皱的薄膜隐隐约约的作响”,声音“喑哑”“尖锐”“短促”“清脆”。当四周的蛙声和其他虫鸣沉寂时,蝈蝈的声音则显得“非常柔和”。这些描述都表现出作者对蝈蝈的喜爱之情。特别是“绿色的蝈蝈啊,如果你拉的琴再响亮一点儿,那你就是比蝉更胜一筹的歌手了。在我国北方,人们却让蝉篡夺了你的名声!”流露出了多么浓厚炽热的感情!

进入第4段,开始写蝈蝈的食物习性,一直写到最后一段,这是文章的主体。这部分 内容是观察金属网罩里的蝈蝈。作者为了了解昆虫的生活习性,不仅到野外去观察,还捉了许多养在家里,这就是他的实验室。蝈蝈长得什么样呢?作者作了一番描述:“非常漂亮,浑身嫩绿,侧面有两条淡白色的丝带,身材优美,苗条匀称,两片大翼轻盈如纱。”优美的语言刻画出蝈蝈可爱的样子。接下来,作者写蝈蝈的食物。作者把蝈蝈和螽斯比较着写,它们都不太喜欢吃莴苣叶。这使作者遇到了“麻烦”。“麻烦”一词表现作者对蝈蝈悉心照料不怕麻烦的态度。作者推测蝈蝈可能吃鲜肉。这样的介绍,与一般的说明文不同。带有明显的感情色彩,亲切自然,富有文学笔法,是法布尔《昆虫记》的特色。这种笔法非常受青少年的欢迎。作者是如何知道蝈蝈最喜欢吃什么食物的呢?一句话,通过观察。清晨,作者散步时看到的一幕揭开了蝈蝈食物之谜——捕蝉为食。那么蝈蝈为什么最喜欢吃蝉的肚子呢?“是不是肚子比其他部位更受欢迎呢?”作者带着这个问题继续实验和观察。第7段写揭开了蝈蝈首先吃蝉肚子的秘密,因为肚子既有肉,又有甜食。8、9、10三段是对蝈蝈食性的补充说明。11段写蝈蝈彼此十分和睦地共居一起,从不争吵。

本文没有丝毫机械呆板的介绍,自始至终饶有兴趣。文中表现出的作者仔细观察,细心揣摩的探索创新精神是十分可贵的,能对学生产生良好的影响。

本文的写作特点很突出:1.文艺笔调。本文不像一般的说明文那样平实,而是灵活生动,不拘一格。既有对昆虫的形象描写,又有个人感情的流露。2.生动传神的语言。作者对蝈蝈充满了喜爱之情,因此在语言的使用上尽量生动感人。比如,“它们对这道菜吃得津津有味”“它毫不犹豫地都接受”“嗉囊装满后,它用喙尖抓抓脚底,用沾着唾液的爪擦擦脸和眼睛,然后闭着双眼或者躺在沙上消化食物”。这些语言都很传神。3.拟人手法的运用。像“蝈蝈在窃窃自语”“蝈蝈酷爱甜食”“蝈蝈是彼此十分和睦地共处在一起的”等都运用了拟人手法。拟人手法的运用,使得文章自然、亲切,增强了可读性。4.通过比较来写蝈蝈。比如在写蝈蝈的叫声时,拿蝉的叫声来作比较;写它喜欢吃肉食时,拿螽斯来作比较;写它追捕蝉时,拿鹰来作比较;写它同类相食时,拿螳螂来作比较。这些比较,既突出了蝈蝈的习性,又说明了作者对各种昆虫的习性了如指掌。

二、问题研究

本文的生字词比较多,教师在教学时要让学生多读几遍,多写几遍,弄清意思。这些词语是:篝火、狩猎、喧嚣、弱肉强食、颚、钳子、、喑哑、静谧、沉寂、更胜一筹、螽斯、莴苣、悬殊、踢蹬、津津有味、嗉囊、喙、吮取、酷爱、螳螂、贪婪、唾液。

这是一篇妙趣横生的文章,教学时要注意调动学生学习的积极性,千万不要上得枯燥乏味。因此,多读,让学生自己讨论是可取的办法。

6、7、8、9、10段都很短,一段一层意思,教师可让学生自己总结。比如教师可以提问:“这五段合并为一段行不行?为什么?”

练习说明

一 快速阅读课文,讨论并完成下列各题。

1.绿色蝈蝈的外表有哪些特征?绿色蝈蝈有哪些习性?作者主要写了哪个方面的习性?

2.作者不断变换对绿色蝈蝈的称呼,找出这些称呼,说说作者在什么情况下用什么称呼,这样写有什么效果。

3.课文多处运用拟人手法,找出几个例子,说说这样写的好处。

参考答案:

1.这道题检查阅读效果,看看学生能否抓住文章的基本内容。参考答案:外表特征,“这种昆虫非常漂亮,浑身嫩绿,侧面有两条淡白色的丝带,身材优美,苗条匀称,两片大翼轻盈如纱。”作者写了蝈蝈的叫声和食性。主要写的是食物习性。

2.作者对蝈蝈的称呼有:狂热的狩猎者、我笼里的囚犯、蝉的屠夫等。当蝈蝈捕杀蝉时作者用“狂热的狩猎者”;当蝈蝈成为作者笼中观察和实验的对象时,作者就用“笼里的囚犯”;当蝈蝈吃蝉肉时作者称之为“蝉的屠夫”。作者不断变换称呼,使行文更生动,描写更形象,给人更深刻的印象。

3.“窃窃自语”“津津有味”“酷爱甜食”“毫不犹豫地都接受”是拟人。这样写亲切自然,形象生动。

二 去户外静听虫鸣鸟啼,辨别这些声音,并用一段话形象地描写出来。

此题旨在鼓励学生开展语文实践活动,实现跨学科交流。

教学建议

一、找法布尔的《昆虫记》(节选本)进行课外阅读,并做读书笔记。

二、注意学习、积累语言。

三、同学之间互相介绍自己最熟悉的一种动物。

有关资料

一、法布尔传略(王光)

1823年12月22日,法布尔降生在法国南部阿韦龙省圣雷翁村一户农民家中。其父安杜瓦纳·法布尔能言善辩,好打抱不平;其母维克陶尔·萨尔格性情温顺,和蔼可亲。但他们是个山乡穷户。

法布尔四岁左右,父母送他到祖母家生活,暂时减轻家庭衣食负担。天真的孩子爱上了祖母家的白鹅、牛犊和绵羊,迷上了户外大自然中的花草虫鸟。

长到七岁,父母接他回家,送他进了村里的小学。校舍条件极其简陋,一间正规房间,一间房顶阁楼。正规房间既当教室,又作厨房、饭堂和睡房,门外就是鸡窝猪圈。老师虽有责任心,却经常无法正常教书,因为他还兼任着本村的剃头匠、旧城堡管理员、敲钟人、唱诗班成员和时钟维修工。

初入学堂,法布尔很不适应,26个法文字母让他花了比别人多几倍的时间,但小法布尔求知欲望格外强烈。他常有机会跑到乡间野外,每次回来,兜里装满了蜗牛、贝壳、蘑菇或其他植物、虫类。

大人一心向往城市生活。法布尔十岁时,小学还没读完,只好随全家迁到本省的罗德茨市去住。父母在那里开了个小咖啡馆,同时安排酷爱学习的小法布尔去罗德茨中学,只随班听课,不在校食宿。这期间,为交足学费,法布尔每逢星期日便去教堂,为弥撒活动做些服务工作,挣回少许酬金。整个中学阶段,法布尔家为生计所迫,几度迁居,又先后在上加龙省的图卢兹市和埃罗纳省的蒙彼利埃市落脚。少年法布尔不得不出门做工谋生,致使中学无法正常读下来。他抓紧一切时间自学,强记勤问。到了15岁那一年,他只身报考沃克吕兹省阿维尼翁市的师范学校,结果被正式录取。

从阿维尼翁师范学校毕业后,法布尔谋得同省卡庞特拉中学初中教员职位,从此开始了长达二十余年的中学教师生涯。

起初,他教数学。一次带学生上户外几何课,忽然在石块上发现了垒筑蜂和蜂窝,被城市生活禁锢了八九年的“虫心”突然焕发。他花了一个月的工资,买到一本昆虫学著作,细读之后,一种抑制不住的强大动力萌生了,他立志要做一个为虫子书写历史的人。那一年他不足19岁。

研究昆虫的决心下定了,但维持生存的职业是教书,法布尔仍须为现实问题苦斗。他先参加有关部门组织的会考,拿到高中毕业资格的业士证书。以后又坚持业余自修,通过各门考试,取得大学资格的物理数学学士学位。24岁的法布尔,由政府教育部门调派到科西嘉岛,担任阿雅克修市中学的教员。他一面努力任教,一面利用业余时间做动植物观察记录。四年后,他被调回阿维尼翁市,担任中学教员。他心目中有个理想:有朝一日能在大学讲课。

两年后,法布尔仍靠自学,取得自然科学学士学位。又过一年,31岁的法布尔以两篇优秀学术论文的实力,一举获得自然科学博士学位。两篇论文的题目分别是:《关于兰科植物节结的研究》和《关于再生器官的解剖学研究及多足纲动物发育的研究》。就在同一年,他在《自然科学年鉴》发表了长期积累的成果——《节腹泥蜂习俗观察记》。《观察记》博得广泛赞赏,法布尔出色的观察才能令人折服,人们公认他不仅纠正了以往权威学者的错误,弥补了前人的疏漏,而且阐发了独到的见解。法布尔的昆虫学文章,开始引起人们的注意。34岁那一年,他发表了关于鞘翅昆虫过变态问题的研究成果,学术质量之精、理论意义之大,令同行刮目相看。法兰西研究院向他颁发了实验生理学奖金,肯定他在活态昆虫上的研究具有不同于昆虫结构解剖学的价值。英国生物学家达尔文格外关注这位年轻的法国人;待1859年《物种起源》问世时人们读到,达尔文称他是“难以效法的观察家”。

博学的法布尔老师,又发现一种从茜草中提取红色染素的工艺,当地政府准备采用他的技术。可是没想到,经过数年周折,工厂主最终建造的是一个人工合成茜红色染料的车间,没有实现他想利用茜草自然资源的“工业化学梦”。这期间,帝国教育部曾以杰出教师的名义为他授勋,主要表彰他在教师岗位上也能从事自然科学研究;他为此还受到拿破仑三世几分钟的接见。放弃化工计划后,为实施教育部长教学改革方案,增设自然课内容,法布尔给女大学生不定期作了一些讲座,听课者越来越多。出于保守、偏见和妒嫉,一群有身份的政界、教育界人物无端指责他是“具有颠覆性的危险人物”,宗教界顽固派攻击他“当着姑娘的面讲植物两性繁殖”。最后由房东出面,强令法布尔全家搬走。法布尔决定离开阿维尼翁这座城市,决心今后再也不想登什么大学讲台。这一年是1870年,法布尔已经46岁。

法布尔携妻室子女进入沃克吕兹省境内,在奥朗日市找到一处安身的家。先丢了饭碗,再花销路费,生活没了着落。一向腼腆的法布尔破天荒开口“求钱”,向只有几面之交的英国著名哲学家密尔(旧译“穆勒”)诉苦,这位英国朋友几年来在阿维尼翁侨居。密尔先生慷慨解囊,法布尔一家度过难关。此后五年间,法布尔主要以撰写自然科学知识读物为生,他的卓越文才开始显露出来。他出版了不少读本,其中包括《天空》《大地》《植物》等讲解性作品,也包括《保尔大叔谈害虫》这样的系列故事性作品。

1875年,长期思考后,法布尔决定远离城市喧嚣,加紧实现整理旧资料、开展新研究的昆虫学工作计划。他带领家人,迁往乡间小镇塞里尼昂。小镇各方面条件较差,甚至没有像样的学校。他鼓励小儿子:在这里能锻炼出强壮的身体和强健的头脑,比在故纸堆里更能发现美和真。经过四年努力,整理二十余年资料而写成的《昆虫记》第一卷,于1879年问世。

1880年,法布尔的宿愿终于实现:他用积攒的一小笔钱,在小镇附近购得一处坐落在生荒地上的老旧民宅,进一步研究活虫子的计划即将变成现实。他精神舒畅,用当地普罗旺斯语给这处居所取了个风趣的雅号——荒石园。年复一年,荒石园主人穿着农民的粗呢子外套,吃着普通老百姓的清汤淡饭,尖镐平铲刨挖,于是,花草争妍,灌木成丛,一座百虫乐园建好了。他守着心爱的荒石园,开足生命的马力,不知疲倦地从事独具特色的昆虫学研究,把劳动成果写进一卷又一卷的《昆虫记》。他就是这样,孤独、欢欣、清苦、平静地度过了35年余生。

《昆虫记》是以大量科学报告材料和文学气质艰苦写成的巨著,文体基本为散文,主体内容集中在昆虫学问题上,同时收入一些讲述经历、回忆往事的传记性文章,若干解决理论问题的议论,以及少量带科普知识性的文字。一位饱经沧桑、追求不止的昆虫学探索者的优势,在这部巨著中得到充分发挥。十卷二百二十余篇,内容丰富自有公论;可其工程之艰难,恐怕只有作者本人才最清楚。法布尔这样说:“散文写作”比求解方程根来得“残酷”。

第十卷脱稿时,他原来不打算把《菜青虫》《萤火虫》两篇编进去,因为这两篇是为计划之中的第十一卷写的。就在这时候,他意识到自己85岁的老身子骨支撑不住了,而且耳聩眼花,手指僵到难以正常写作的地步。最后,他心中埋没了“第十一卷”的念头,毅然将两篇文章定为第十卷的增补篇。1910年,他已过86岁,第十卷问世了。他抱着书,拄着拐杖,装上放大镜,一步三摇,流连在“荒石园”中,仍想再把《昆虫记》写下去……但老人的心愿难以实现了。

就在这一年,家人以“从事《昆虫记》写作五十周年”之名,邀集法布尔的挚友和学界友好来到“荒石园”,为他举行一次小型庆祝会。法布尔倍感安慰,热泪盈眶。消息传出,舆论界大哗大惊:法国人居然把隐居“荒石园”中的这位值得骄傲的同胞忘得如此轻松!法布尔不在乎这“疏忽”,他正开始筹划出版全十卷精装本《昆虫记》,并亲自为这一版本写下一篇短短的序言。序言结尾是这样几句话:“非常遗憾,如今我被迫中断了这些研究。要知道从事这些研究,是我一生得到的惟一仅有的安慰。阅尽大千世界,自知虫类是其最多姿多彩者中之一群。即使能让我再获得些许气力,甚至有可能再获得几次长寿人生,我也做不到彻底认清虫类的益趣。”

呵呵,建议你下了解一下杀毒软件的工作机制。

金山,360,瑞星等杀毒软件,都是驱动保护的,bat因为比它高层,所以做不到关闭杀毒软件。否则连批处理都可轻易攻破,那早就有无数病毒泛滥了。只有汇编语言这样的底层语言才可以,(其实C语言也能做到)。当然,bat也不是不行,可以用bat汇编,叫做ASCIICoding技术,挺难的。2007年以前国内还没有一个会的(除非会但不说,那我当然就不知道了)。也建议你学习Rootkit Hook技术,可以读一读这篇文章。

瘟神的尾行--Rootkit技术发展史

作者:小金

一. 无法驱逐的“助手”

网管小张正在手忙脚乱的寻找他的手工杀毒工具包,因为他在安装一个网管工具的时候无意中走了神,点击了“下一步”按钮后才惊觉安装程序的界面里一个不引人注目的角落里写着“安装CNNIC网络实名”这一行小字,而且最开头部分有一个小小的勾。于是著名的“中国网民的得力助手”便理所当然的在他的机器里安了家。

心里把厂商骂了十八遍的小张终于翻出了他外出修机时最得意的工具IceSword和超级巡警,果然在进程列表和SSDT列表里发现了红色警报,小张笑了笑,对付这些一般用户无法卸载的恶意流氓,自己可谓经验丰富了,当下便三下五除二的把CNNIC的进程给终结了,SSDT也给恢复了初始状态,然后小张去删除注册表启动项——突然发出的一个错误提示声音把小张吓了一跳,再定睛一看,他的笑容凝固了:“删除项时出错”。不会吧?小张急忙去删除CNNIC目录,结果彻底愣在了那里,系统弹出的错误提示很明确的告诉他,“无法删除文件,文件可能正在被使用”。怎么回事?小张一下子没了头绪……

达尔文的进化论告诉我们,“物竞天择,适者生存”,同样,在这安全与入侵的网络世界里,也在进行着这样一场选择的过程……

二. 被AIDS纠缠的互联网

。。。。。。。。。

。。。。。。。。。。。。。

。。。。。。。。。。。。。。(百度长度限制。。。想看全篇自己搜吧)

三. 结语

虽然到处都在提倡和谐网络的普及,但是,“健康上网”仅仅是指代那些黄赌毒而已吗?在利益面前,开发者的正义感越发渺小起来,我们的网络世界,是被瘟神紧紧跟随着的。技术的斗争越发激烈,但是用户的电脑知识是不会跟着时代发展而自动填充的,最终,大众上网的人民成了这一切技术较量的受害者。

这个荒谬的发展方向,何时才能休止呢?

还有这篇:

对大多数的Windows开发者来说,如何在Win32系统中对API函数的调用进行拦截一直是项极富挑战性的课题,因为这将是对你所掌握的计算机知识较为全面的考验,尤其是一些在如今使用RAD进行软件开发时并不常用的知识,这包括了操作系统原理、汇编语言甚至是机器指令(听上去真是有点恐怖,不过这是事实)。

当前广泛使用的Windows操作系统中,像Win 9x和Win NT/2K,都提供了一种比较稳健的机制来使得各个进程的内存地址空间之间是相互独立,也就是说一个进程中的某个有效的内存地址对另一个进程来说是无意义的,这种内存保护措施大大增加了系统的稳定性。不过,这也使得进行系统级的API拦截的工作的难度也大大加大了。

当然,我这里所指的是比较文雅的拦截方式,通过修改可执行文件在内存中的映像中有关代码,实现对API调用的动态拦截;而不是采用比较暴力的方式,直接对可执行文件的磁盘存储中机器代码进行改写。

二、API钩子系统一般框架

通常,我们把拦截API的调用的这个过程称为是安装一个API钩子(API Hook)。一个API钩子基本是由两个模块组成:一个是钩子服务器(Hook Server)模块,一般为EXE的形式;一个是钩子驱动器(Hook Driver)模块,一般为DLL的形式。

钩子服务器主要负责向目标进程注入钩子驱动器,使得钩子驱动器运行在目标进程的地址空间中,这是关键的第一步,而钩子驱动器则负责实际的API拦截处理工作,以便在我们所关心的API函数调用的之前或之后能做一些我们所希望的工作。一个比较常见的API钩子的例子就是一些实时翻译软件(像金山词霸)中必备的的功能:屏幕抓词。它主要是对一些Win32 API中的GDI函数进行了拦截,获取它们的输入参数中的字符串,然后在自己的窗口中显示出来。

针对上述关于API钩子的两个部分,有以下两点需要我们重点考虑的: 选用何种DLL注入技术,以及采用何种API拦截机制。

三、注入技术的选用

由于在Win32系统中各个进程的地址是互相独立的,因此我们无法在一个进程中对另一个进程的代码进行有效的修改,但如果你要完成API钩子的工作又必须如此。因此,我们必须采取某种独特的手段,使得API钩子(准确的说是钩子驱动器)能够成为目标进程中的一部分,才有较大的可能来对目标进程数据和代码进行有控制的修改。

通常可采用的几种注入方式:

1.利用注册表

如果我们准备拦截的进程连接了User32.dll,也就是使用了 User32.dll中的API(一般图形界面的应用程序都是符合这个条件),那么就可以简单把你的钩子驱动器DLL的名字作为值添加在下面注册表的键下: HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs 值的形式可以为单个DLL的文件名,或者是一组DLL的文件名,相邻的名称之间用逗号或空格间隔。所有由该值标识的DLL将在符合条件的应用程序启动的时候装载。这是一个操作系统内建的机制,相对其他方式来说危险性较小,但它也有一些比较明显的缺点:该方法仅适用于NT/2K操作系统,显然看看键的名称就可以明白;如果需要激活或停止钩子的注入,只有重新启动Windows,这个就似乎太不方便了;最后一点也很显然,不能用此方法向没有使用User32.dll的应用程序注入DLL,例如控制台应用程序等。另外,不管是否为你所希望,钩子DLL将注入每一个GUI应用程序,这将导致整个系统性能的下降!

2.建立系统范围的Windows钩子

要向某个进程注入DLL,一个十分普遍也是比较简单的方法就是建立在标准的Windows钩子的基础上。Windows钩子一般是在DLL中实现的,这是一个全局性的Windows钩子的基本要求,这也很符合我们的需要。当我们成功地调用SetWindowsHookEx函数之后,便在系统中安装了某种类型的消息钩子,这个钩子可以是针对某个进程,也可以是针对系统中的所有进程。一旦某个进程中产生了该类型的消息,操作系统会自动把该钩子所在的DLL映像到该进程的地址空间中,从而使得消息回调函数(在 SetWindowsHookEx的参数中指定)能够对此消息进行适当的处理,在这里,我们所感兴趣的当然不是对消息进行什么处理,因此在消息回调函数中只需把消息钩子向后传递就可以了,但是我们所需的DLL已经成功地注入了目标进程的地址空间,从而可以完成后续工作。

我们知道,不同的进程之间是不能直接共享数据的,因为它们活动在不同的地址空间中。但在Windows钩子 DLL中,有一些数据,例如Windows钩子句柄HHook,这是由SetWindowsHookEx函数返回值得到的,并且作为参数将在 CallNextHookEx函数和UnhookWindoesHookEx函数中使用,显然使用SetWindowsHookEx函数的进程和使用 CallNextHookEx函数的进程一般不会是同一个进程,因此我们必须能够使句柄在所有的地址空间中都是有效的有意义的,也就是说,它的值必须必须在这些钩子DLL所挂钩的进程之间是共享的。为了达到这个目的,我们就应该把它存储在一个共享的数据区域中。

在VC++中我们可以采用预编译指令#pragma data_seg在DLL文件中创建一个新的段,并且在DEF文件中把该段的属性设置为"shared",这样就建立了一个共享数据段。对于使用 Delphi的人来说就没有这么幸运了:没有类似的比较简单的方法(或许是有的,但我没有找到)。不过我们还是可以利用内存映像技术来申请使用一块各进程可以共享的内存区域,主要是利用了CreateFileMapping和MapViewOfFile这两个函数,这倒是一个通用的方法,适合所有的开发语言,只要它能直接或间接的使用Windows的API。

在Borland的BCB中有一个指令#pragma codeseg与VC++中的#pragma data_seg指令有点类似,应该也能起到一样的作用,但我试了一下,没有没有效果,而且BCB的联机帮助中对此也提到的不多,不知怎样才能正确的使用(或许是另外一个指令,呵呵)。

一旦钩子DLL加载进入目标进程的地址空间后,在我们调用UnHookWindowsHookEx函数之前是无法使它停止工作的,除非目标进程关闭。

这种DLL注入方式有两个优点: 这种机制在Win 9x/Me和Win NT/2K中都是得到支持的,预计在以后的版本中也将得到支持;钩子DLL可以在不需要的时候,可由我们主动的调用 UnHookWindowsHookEx来卸载,比起使用注册表的机制来说方便了许多。尽管这是一种相当简洁明了的方法,但它也有一些显而易见的缺点:首先值得我们注意的是,Windows钩子将会降低整个系统的性能,因为它额外增加了系统在消息处理方面的时间;其次,只有当目标进程准备接受某种消息时,钩子所在的DLL才会被系统映射到该进程的地址空间中,钩子才能真正开始发挥作用,因此如果我们要对某些进程的整个生命周期内的API调用情况进行监控,用这种方法显然会遗漏某些API的调用 。

3.使用 CreateRemoteThread函数

在我看来这是一个相当棒的方法,然而不幸的是,CreateRemoteThread这个函数只能在Win NT/2K系统中才得到支持,虽然在Win 9x中这个API也能被安全的调用而不出错,但它除了返回一个空值之外什么也不做。该注入过程也十分简单:我们知道,任何一个进程都可以使用 LoadLibrary来动态地加载一个DLL。但问题是,我们如何让目标进程(可能正在运行中)在我们的控制下来加载我们的钩子DLL(也就是钩子驱动器)呢?有一个API函数CreateRemoteThread,通过它可在一个进程中可建立并运行一个远程的线程--这个好像和注入没什么关系嘛?往下看!

调用该API需要指定一个线程函数指针作为参数,该线程函数的原型如下: Function ThreadProc(lpParam: Pointer): DWORD,我们再来看一下LoadLibrary的函数原型: Function LoadLibrary(lpFileName: PChar): HModule。发现了吧!这两个函数原型几乎是一样的(其实返回值是否相同关系不大,因为我们是无法得到远程线程函数的返回值的),这种类似使得我们可以把直接把LoadLibrary当做线程函数来使用,从而在目标进程中加载钩子DLL。

与此类似,当我们需要卸载钩子DLL时,也可以FreeLibrary作为线程函数来使用,在目标进程中卸载钩子DLL,一切看来是十分的简洁方便。通过调用GetProcAddress函数,我们可以得到LoadLibrary函数的地址。由于 LoadLibrary是Kernel32中的函数,而这个系统DLL的映射地址对每一个进程来说都是相同的,因此LoadLibrary函数的地址也是如此。这点将确保我们能把该函数的地址作为一个有效的参数传递给CreateRemoteThread使用。 FreeLibrary也是一样的。

AddrOfLoadLibrary := GetProcAddress(GetModuleHandle(‘Kernel32.dll'), ‘LoadLibrary')

HRemoteThread := CreateRemoteThread(HTargetProcess, nil, 0, AddrOfLoadLibrary, HookDllName, 0, nil)

要使用CreateRemoteThread,我们需要目标进程的句柄作为参数。当我们用 OpenProcess函数来得到进程的句柄时,通常是希望对此进程有全权的存取操作,也就是以PROCESS_ALL_ACCESS为标志打开进程。但对于一些系统级的进程,直接这样显然是不行的,只能返回一个的空句柄(值为零)。为此,我们必须把自己设置为拥有调试级的特权,这样将具有最大的存取权限,从而使得我们能对这些系统级的进程也可以进行一些必要的操作。

4.通过BHO来注入DLL

有时,我们想要注入DLL的对象仅仅是Internet Explorer,很幸运,Windows操作系统为我们提供了一个简单的归档方法(这保证了它的可靠性!)―― 利用Browser Helper Objects(BHO)。一个BHO是一个在 DLL中实现的COM对象,它主要实现了一个IObjectWithSite接口,而每当IE运行时,它会自动加载所有实现了该接口的COM对象。

四、拦截机制

在钩子应用的系统级别方面,有两类API拦截的机制――内核级的拦截和用户级的拦截。内核级的钩子主要是通过一个内核模式的驱动程序来实现,显然它的功能应该最为强大,能捕捉到系统活动的任何细节,但难度也较大,不在本文的探讨范围之内(尤其对我这个使用Delphi的人来说,还没涉足这块领域,因此也无法探讨,呵呵)。

而用户级的钩子则通常是在普通的DLL中实现整个API的拦截工作,这才是此次重点关注的。拦截API函数的调用,一般可有以下几种方法:

1. 代理DLL(特洛伊木马

一个容易想到的可行的方法是用一个同名的DLL去替换原先那个输出我们准备拦截的API所在的DLL。当然代理DLL也要和原来的一样,输出所有函数。但如果想到DLL中可能输出了上百个函数,我们就应该明白这种方法的效率是不高的,估计是要累死人的。另外,我们还不得不考虑DLL的版本问题,很是麻烦。

2.改写执行代码

有许多拦截的方法是基于可执行代码的改写,其中一个就是改变在CALL指令中使用的函数地址,这种方法有些难度,也比较容易出错。它的基本思路是检索出在内存中所有你所要拦截的API的CALL指令,然后把原先的地址改成为你自己提供的函数的地址。

另外一种代码改写的方法的实现方法更为复杂,它的主要的实现步骤是先找到原先的API函数的地址,然后把该函数开始的几个字节用一个JMP指令代替(有时还不得不改用一个INT指令),从而使得对该API函数的调用能够转向我们自己的函数调用。实现这种方法要牵涉到一系列压栈和出栈这样的较底层的操作,显然对我们的汇编语言和操作系统底层方面的知识是一种考验。这个方法倒和很多文件型病毒的感染机制相类似。

3.以调试器的身份进行拦截

另一个可选的方法是在目标函数中安置一个调试断点,使得进程运行到此处就进入调试状态。然而这样一些问题也随之而来,其中较主要的是调试异常的产生将把进程中所有的线程都挂起。它也需要一个额外的调试模块来处理所有的异常,整个进程将一直在调试状态下运行,直至它运行结束。

4.改写PE文件的输入地址表

这种方法主要得益于现如今Windows系统中所使用的可执行文件(包括EXE文件和DLL文件)的良好结构――PE文件格式(Portable Executable File Format),因此它相当稳健,又简单易行。要理解这种方法是如何运作的,首先你得对PE文件格式有所理解。

一个PE文件的结构大致如下所示:一般PE文件一开始是一段DOS程序,当你的程序在不支持Windows的环境中运行时,它就会显示"This Program cannot be run in DOS mode"这样的警告语句;接着这个DOS文件头,就开始真正的PE文件内容了,首先是一段称为"IMAGE_NT_HEADER"的数据,其中是许多关于整个PE文件的消息,在这段数据的尾端是一个称为Data Directory的数据表,通过它能快速定位一些PE文件中段(section)的地址;在这段数据之后,则是一个"IMAGE_SECTION_HEADER"的列表,其中的每一项都详细描述了后面一个段的相关信息;接着它就是PE文件中最主要的段数据了,执行代码、数据和资源等等信息就分别存放在这些段中。

在所有的这些段里,有一个被称为".idata"的段(输入数据段)值得我们去注意,该段中包含着一些被称为输入地址表(IAT,Import Address Table)的数据列表,每个用隐式方式加载的API所在的DLL都有一个IAT与之对应,同时一个API的地址也与IAT中一项相对应。当一个应用程序加载到内存中后,针对每一个API函数调用,相应的产生如下的汇编指令:

JMP DWORD PTR [XXXXXXXX]

如果在VC++中使用了_delcspec(import),那么相应的指令就成为:

CALL DWORD PTR [XXXXXXXX]。

不管怎样,上述方括号中的总是一个地址,指向了输入地址表中一个项,是一个DWORD,而正是这个 DWORD才是API函数在内存中的真正地址。因此我们要想拦截一个API的调用,只要简单的把那个DWORD改为我们自己的函数的地址,那么所有关于这个API的调用将转到我们自己的函数中去,拦截工作也就宣告顺利的成功了。这里要注意的是,自定义的函数的调用约定应该是API的调用约定,也就是 stdcall,而Delphi中默认的调用约定是register,它们在参数的传递方法等方面存在着较大的区别。

另外,自定义的函数的参数形式一般来讲和原先的API函数是相同的,不过这也不是必须的,而且这样的话在有些时候也会出现一些问题,我在后面将会提到。因此要拦截API的调用,首先我们就要得到相应的IAT的地址。系统把一个进程模块加载到内存中,其实就是把 PE文件几乎是原封不动的映射到进程的地址空间中去,而模块句柄HModule实际上就是模块映像在内存中的地址,PE文件中一些数据项的地址,都是相对于这个地址的偏移量,因此被称为相对虚拟地址(RVA,Relative Virtual Address)。

于是我们就可以从HModule开始,经过一系列的地址偏移而得到IAT的地址。不过我这里有一个简单的方法,它使用了一个现有的API函数ImageDirectoryEntryToData,它帮助我们在定位IAT时能少走几步,省得把偏移地址弄错了,走上弯路。不过纯粹使用RVA从HModule开始来定位IAT的地址其实并不麻烦,而且这样还更有助于我们对PE文件的结构的了解。上面提到的那个API 函数是在DbgHelp.dll中输出的(这是从Win 2K才开始有的,在这之前是由ImageHlp.dll提供的),有关这个函数的详细介绍可参见MSDN。

在找到IAT之后,我们只需在其中遍历,找到我们需要的API地址,然后用我们自己的函数地址去覆盖它,下面给出一段对应的源码:

procedure RedirectApiCallvar ImportDesc:PIMAGE_IMPORT_DESCRIPTORFirstThunk:PIMAGE_THUNK_DATA32sz:DWORD

begin

//得到一个输入描述结构列表的首地址,每个DLL都对应一个这样的结构 ImportDesc:=ImageDirectoryEntryToData(Pointer(HTargetModule), true, IMAGE_DIRECTORY_ENTRY_IMPORT, sz)

while Pointer(ImportDesc.Name)<>nil do

begin //判断是否是所需的DLL输入描述

if StrIComp(PChar(DllName),PChar(HTargetModule+ImportDesc.Name))=0 then begin

//得到IAT的首地址

FirstThunk:=PIMAGE_THUNK_DATA32(HTargetModule+ImportDesc.FirstThunk)

while FirstThunk.Func<>nil do

begin

if FirstThunk.Func=OldAddressOfAPI then

begin

//找到了匹配的API地址 ......

//改写API的地址

break

end

Inc(FirstThunk)

end

end

Inc(ImportDesc)

end

end

最后有一点要指出,如果我们手工执行钩子DLL的退出目标进程,那么在退出前应该把函数调用地址改回原先的地址,也就是API的真正地址,因为一旦你的DLL退出了,改写的新的地址将指向一个毫无意义的内存区域,如果此时目标进程再使用这个函数显然会出现一个非法操作。

五、替换函数的编写

前面关键的两步做完了,一个API钩子基本上也就完成了。不过还有一些相关的东西需要我们研究一番的,包括怎样做一个替换函数。 下面是一个做替换函数的步骤: 首先,不失一般性,我们先假设有这样的一个API函数,它的原型如下:

function SomeAPI(param1: Pcharparam2: Integer): DWORD

接着再建立一个与之有相同参数和返回值的函数类型:

type FuncType= function (param1: Pcharparam2: Integer): DWORD

然后我们把SomeAPI函数的地址存放在OldAddress指针中。接着我们就可以着手写替换函数的代码了:

function DummyFunc(param1: Pcharparam2: Integer): DWORDbegin ......

//做一些调用前的操作

//调用被替换的函数,当然也可以不调用

result := FuncType(OldAddress) (param1 , param2)

//做一些调用后的操作

end

我们再把这个函数的地址保存到NewAddress中,接着用这地址覆盖掉原先API的地址。这样当目标进程调用该API的时候,实际上是调用了我们自己的函数,在其中我们可以做一些操作,然后在调用原先的API函数,结果就像什么也没发生过一样。当然,我们也可以改变输入参数的值,甚至是屏蔽调这个API函数的调用。

尽管上述方法是可行的,但有一个明显的不足:这种替换函数的制作方法不具有通用性,只能针对少量的函数。如果只有几个API要拦截,那么只需照上述说的重复做几次就行了。但如果有各种各样的API要处理,它们的参数个数和类型以及返回值的类型是各不相同的,仍然采用这种方法就太没效率了。

的确是的,上面给出的只是一个最简单最容易想到的方法,只是一个替换函数的基本构架。正如我前面所提到的,替换函数的与原先的API函数的参数类型不必相同,一般的我们可以设计一个没有调用参数也没有返回值的函数,通过一定的技巧,使它能适应各种各样的API 函数调用,不过这得要求你对汇编语言有一定的了解。

首先,我们来看一下执行到一个函数体内前的系统堆栈情况(这里函数的调用方式为stdcall),函数的调用参数是按照从右到左的顺序压入堆栈的(堆栈是由高端向低端发展的),同时还压入了一个函数返回地址。在进入函数之前,ESP正指向返回地址。因此,我们只要从ESP+4开始就可以取得这个函数的调用参数了,每取一个参数递增4。另外,当从函数中返回时,一般在EAX中存放函数的返回值。

了解了上述知识,我们就可以设计如下的一个比较通用的替换函数,它利用了Delphi的内嵌式汇编语言的特性。

Procedure DummyFunc

asm add esp,4 mov eax,esp//得到第一个参数

mov eax,esp+4//得到第二个参数 ......

//做一些处理,这里要保证esp在这之后恢复原样

call OldAddress //调用原先的API函数 ......

//做一些其它的事情

end

当然,这个替换函数还是比较简单的,你可以在其中调用一些纯粹用OP语言写的函数或过程,去完成一些更复杂的操作(要是都用汇编来完成,那可得把你忙死了),不过应该把这些函数的调用方式统一设置为stdcall方式,这使它们只利用堆栈来传递参数,因此你也只需时刻掌握好堆栈的变化情况就行了。如果你直接把上述汇编代码所对应的机器指令存放在一个字节数组中,然后把数组的地址当作函数地址来使用,效果是一样的。

六、后记

做一个API钩子的确是件不容易的事情,尤其对我这个使用Delphi的人来说,为了解决某个问题,经常在OP、C++和汇编语言的资料中东查西找,在程序调试中还不时的发生一些意想不到的事情,弄的自己是手忙脚乱。不过,好歹总算做出了一个 API钩子的雏形,还是令自己十分的高兴,对计算机系统方面的知识也掌握了不少,受益非浅。当初在写这篇文章之前,我只是想翻译一篇从网上Down下来的英文资料(网址为 ,文章名叫"API Hook Revealed",示例源代码是用VC++写的,这里不得不佩服老外的水平,文章写得很有深度,而且每个细节都讲的十分详细)。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/121638.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-14
下一篇2023-03-14

发表评论

登录后才能评论

评论列表(0条)

    保存