我的日志本

来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/archive.php?id=1712 存档链接: https://web.archive.org/web/20041222122419id_/http://www.blogbus.com:80/blogbus/blog/archive.php?id=1712


我的日志本 2003/12/1 到 2003/12/31 但愿它对我有用;但愿它对你有用。 备忘: About ASProtect

2003-12-31 09:18 There are multiple ways of obtaining OEP of AsProtect file in Ollydbg. Here one:

  1. Execute file as normal, counting the number of exceptions. Pass each exception to prog.
  2. Restart program, count the number of exceptions - 1.
  3. ALT-M, Right click memory address that is app code. Set break on access.
  4. Run prog. Ollydbg will break on OEP. Post by lgx @ 09:18 .hlp to .chm?

2003-12-28 02:12 google 半天都没找到好的解决办法,气愤。唯一的解决办法是先用 helpdeco 反编译 .hlp,再用 Help Workshop 编译成 .chm ,不过效果很不理想。 搞不懂为什么有人( idapro 和 ollydbg ) 非要把文档做成 .hlp,看着很累。 Post by lgx @ 02:12 Merry Xmas!

2003-12-24 21:37 Post by lgx @ 21:37 VISUAL BASIC 逆向工程-反编译步骤 [zz]

2003-12-24 10:41 VISUAL BASIC 逆向工程-反编译步骤 可能的话,写个 idc 自动做。 Post by lgx @ 10:41 关于 cookie 设不上问题

2003-12-23 11:23 事实上,没有过期时间的 cookie 都可以设置上,有过期时间的却设不上。 有的说是客户端和服务端时间太不一致,但是我把时间改成一致也不行。 去 php.net 看 setcookie 函数说明,发现有人提到如果时区设置不对,可能导致 IE 6 cookie设置不上。看 Server 端好像没什么问题,看客户端时区,发现是 USA/Canada , 改成 GMT+8 (BeiJing),再修正时间 ,就 ok 啦。 blogbus 服务器的时间不知道对不对。 Post by lgx @ 11:23 一个郁闷很久的apache问题解决办法

2003-12-22 16:46 在 RedHat Linux 上,重新编译内核后有时候导致 apache 无法启动,报告一些锁相关函数没有实现。 有时候重新编译 apache 可以解决,有时候解决不了。 今天又遇到。同样的 RedHat 9,同样的 Kernel,同样的 apache,一台机器正常另一台报错。去 apache bugtraq 准备提交给 apache group 解决,发现上面有类似问题报告(参考: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10631 )。下面是原文引用: Dear sirs, I upgraded from apache 2.0.36 to 2.0.39 and compiled it with ./configure make ; make install Everything went OK, however after ./apachectl start httpd remain down and in log file appeared "Couldn't accept serialization lock file: Function not implemented" (without even modyfing httpd.conf)

I am running Slackware 8.0 with 2.4.18 kernel (no kernel supprot for modules) With 2.0.36 version everything worked with default install well. Am I missing something here? I am trying to solve this since the exploit was discovered and no success. Thanks in advance. Jan Kavan ------- Additional Comments From Jeff Trawick 2002-07-26 12:59 ------- You don't seem to have SysV semaphores enabled in your kernel. (If you are doubtful of this, run "strace -f apachectl start" to see what syscall fails before Apache writes the log message and exits. It is probably semget() or semctl().)

Put "AcceptMutex fcntl" in your httpd.conf to work around this problem. 解决办法可行,但是问题原因解释不对。因为 SysV IPC 我已经编译进内核, 这个问题应该是出在 RedHat 修改标准 c 库里。 Post by lgx @ 16:46 在家里登录不上blogbus啦 :(

2003-12-22 12:55 郁闷。无缘无故的,好像是 IE Bug。安全设置降到最低也不行。做产品时也遇到这种问题:登录成功后 cookie 却设置不上,突然就设不上了。 Post by lgx @ 12:55 libtomcrypt

2003-12-22 12:53 一个crypt库: http://libtomcrypt.org 。它的优点是很容易单独抽出一种算法使用。 Post by lgx @ 12:53 户外活动 :)

2003-12-20 17:10 今天阳光灿烂,风很小。北京的冬天难得有这样的好天气。于是和LP一起去奥体逛逛,晒晒太阳,看看鸽子。 东门寰岛 和平鸽广场 Post by lgx @ 17:10 关于 VB 和 COM

2003-12-20 01:59 VB 程序的 Message Box 调的是 rtcMsgBox ,rtcMsgBox 调用 MessageBoxIndirectA 实现。 要调试一个 COM 对象,可以写一个 vbs 脚本,通过 CreateObject 加载对象,然后在 wscript.exe 上调试。 Post by lgx @ 01:59 关于 Delphi

2003-12-20 01:51 Delphi 程序中 垃圾代码很多 。因此Reverse时要多用F8。 通常对 C 程序有效的断点方法对 Delphi 无效。一个简单的 MessageBox Delphi都没有调MessageBox API,而是自己实现的 (可能Delphi程序很大就是这种原因),只能在 CreateWindowEx 上拦截。 Post by lgx @ 01:51 改版啦!

2003-12-19 11:05 算 v 0.9 吧。blogbus 的模板 table 用的太多,基本上都是用 table 搭框架。用 table 速度慢, 容易出问题 。以后有兴趣继续修改。 Post by lgx @ 11:05 奇怪事情

2003-12-16 20:04 看手机 17:47 有个未接来电(68401004), 打过去却说是空号,没有这个号码! Post by lgx @ 20:04 造化的报应 (节选自吴思《潜规则》)

2003-12-16 14:49 来自: http://ror.cn/perl/ut/topic_show.cgi?id=197895&h=1&bpg=1&age=30 造化的报应 (节选自吴思《潜规则》) 一 北京街头的十字路口有红绿灯,红绿灯下还有警察。通常还不是一个两个警察,而是四五个警察。这些警察都是要拿工资的,而这些工资来自税收,本来那是企业的利润,可以成为生产的动力和更多的就业机会。降低税收可以刺激生产,提高人们的生活水平,这是大家都明白的道理。那么在警察工资方面的开支能不能减少呢? 美国的红绿灯下没有警察,人们仍然能遵守交通规则。人们对交通规则的遵守竟然可以到这种地步:明明没有车辆,一个人在人行横道的路口也会等待变灯。我在赫尔辛基就遇到过这样的事情。一位中年妇女在马路对面等待变灯,于是我也不好意思横穿空空荡荡的马路,一直等到红灯变绿。在中国,这当然是极其罕见的事情。这就是说,在美国和我说的那个欧洲国家,警察的工资是可以省下来的。省了下来,交通秩序并不会变坏。(1) 但是我确信,中国不可以节省这笔钱。至少在我非常熟悉的北京街头,红绿灯下的许多警察是绝对必要的。如果没有警察,只有红绿灯,我确信,这个路口就如同没有红绿灯一样,必定会拥挤得一塌糊涂。不用说别人,我本人也会跟着人们一块去挤。我经历过这样的事情,如果我单方面谦让,别人肯定不会让我,我永远也没有过路的机会。道德的约束本来就是非常脆弱的。如果有几个人不理睬红绿灯硬闯,这条路就要堵塞,我们这些打算遵守交通规则的人也就不能遵守,也没有必要遵守了。 当然,警察的工资也不是绝对不可减少。譬如,四五个也可以减少到两个。只要在岗的人认真负责,应该可以维持交通规则的威严。如此威严久了,再将人降低到两个,最后减少到一个,也是可以的。但是这要求警察的工作量和责任心大大超过国家公务员的平均水平,似乎有些不合情理。 我想由此说明的是,中国人自我约束意识弱,道德水准低,导致了政府的臃肿和税收的增加,导致了社会生活质量的下降。这原因不在别的地方,其实和我们每个人都有一些关系。我们活该。仅仅收入减少倒也罢了,我们非常在乎的国际面子也大受影响,我们的个人尊严因此蒙上了阴影。 欧美的红绿灯无须警察压阵,这已经显出了人家的公德水平。德国的地铁竟不用验票,因为人人自觉买票,这更显出了人家的高超。而我们中国人在国外干什么呢?在日本打投币电话,竟然在中国人中流传着一种诀窍,用线拴住硬币,用完了再将其吊出来。这真是极其鲜明的对比。我的一个非常能干也很有教养的朋友在德国吃饭,他说自己遵守了一切礼仪,也按常规付了小费,但是仍然能清楚地感觉到侍者对他的轻蔑。他说,他知道这不是对他本人的侮辱,侍者看不起的是他所代表的民族。我们中国人自己也看不起自己,只要条件相同,宁可与外国人做生意,躲开自己的同胞,因为他们失信和欺骗的可能性更高。 于是,我们的民族就遭到了报应,变成一个令人厌恶也彼此厌恶的民族。变成一个只讲利害关系,一有机会就坑蒙拐骗的人群。为什么会这样呢?为什么欧美国家的公德水平比我们高呢?为什么我们的人民不肯遵守明明对自己有利,谁都知道是非常必要的交通规则呢?按说,交通规则并不是什么复杂问题,并不需要多么高超的理性和信仰支撑。 二 我有一个猜测,可以部分解释为什么骑自行车的人缺乏自觉精神,非要警察监督不可。我承认一些人自制力差,像儿童一样需要父母监督。但这不足以解释大众的行为。毕竟在大街上走的多数是成年人,他们在工作单位里很能忍气吞声,自制力并不弱,他们所欠缺的似乎只是公德心。而公德心是对一种对自我与公共事务的关系的判断和肯定。 中国老百姓认为自己是什么人?在与国家的关系方面,他们到底是什么? 如果我们果真把自己当成了国家的主人,就像理论上应该的那样,我们交了税,雇人来管理交通,这些交通管理人员是我们的公仆,那么,我们会如何看待我们委托他们照应的这些事情?--我们大概会像一个主人那样,自觉小心地关照家里的秩序,并且提醒警察要认真负责地维护秩序,好好干活,不要偷懒。毕竟我们是给他开工资的。我们不会把公共交通当成那些官吏和衙役的事情,我们明白这是我们的事情。 这使得我想到了一个朋友说到的故事。他说他在美国见过一件事情,印象很深。一个老头,看见路口堵车,很生气,就下车把维持交通的警察训斥了一顿。说我们交了税,应该得到好的服务,你怎么把交通弄成这样?警察毕恭毕敬地听他训斥。这在中国显然是不可思议的。至少对我来说,很习惯听警察的训斥,从来没有妄想过训斥警察。在我的体会里,中国的警察和司机的关系,属于典型的猫和老鼠的关系。 老鼠--这就是中国百姓心目中的真实的自我形象。猫和老鼠--这就是真实的自己与公家的关系的真相。中国百姓很少有人当真认为自己是国家的主人。因为这不是事实。公共事务一直是皇上和官吏们垄断的事情,老百姓一直在躲避他们的惩罚、勒索和敲诈。在这方面,老百姓就是缺乏责任心,因为这确实不是百姓能够负责的领域。如果有谁不懂事,企图按照主人的方式行事,对了领导的心思则已,对不上就会碰得头破血流,海瑞和彭德怀就是证明。那些地位甚高的名臣尚且如此,更何况普通百姓。 按照传统习惯,也按照我们对现实的认识,公共交通搞得好,这是领导有方,是皇上圣明和皇恩浩荡。我们要感谢政府把北京的交通整顿得那么好,让我们生活得那么方便。譬如出租车不许在长安街路边停靠,据说是为了方便管理。如果我们人民真把自己当成主人,这岂不成了仆人为了自己方便而禁止主人进家门?主人又如何能心平气和?还有一个例子是高官的座车通过大街,所有的立交行人天桥都要封锁。我曾问过封锁交通的便衣为什么要这样,他教育我说,要服从国家利益,要遵守国家的纪律。国家利益和纪律在此又表现出了和我们正常走路的老百姓的对立。这样的经历多了,我们自然会认为国家的事情不是我们的事情,那是官员的事情,让他们自己操心去好了。 在这样的关系中,中国百姓找到了自己的定位。在根基上,他就不认为自己是主人。主人进了家门,难道还需要他聘请的小时工提醒他,要换掉沾满了泥的雨靴再踩地毯么?反过来说,如果我们踩地毯前没有换鞋,而我们又不是不懂事的小孩,恐怕正因为这里不是自己家,连亲戚朋友的家也不是。我们不认为那些换鞋的规矩是自己的规矩,那是官们制订出来管制我们的规矩。其实,不仅在红绿灯前,就是在官场上,这种糟蹋地毯的心态也是很常见的。官员不过是皇上的雇员,能偷懒不妨偷懒。皇上吃香的喝辣的,进进出出还要让小兵小官给他站岗开道,本来心理已经不那么平衡了。凭什么还要对他忠心耿耿? 我愿意遵守交通规则,至少不想首先破坏交通规则,是因为我把自己看成一个好人,一个有道德的人,一个己所不欲勿施于人的人。说得自负一点,我耻于把自己降低到那些抢红灯抢座位的人的水平。我觉得自己比他们高得多。而我的这种自我期许的基础又来自哪里呢?我曾经以为自己是一个忧国忧民忧天下的人。国家的事情就是我的事情,民族的事情也是我的事情,人类的事情还是我的事情。我是真把自己当成主人的。秩序是我的秩序,交通是我的交通。我不认为那是警察的事情。我还用警察管么?我那么低档么? 我的这种认识和期许最初来自轻信,来自少年时代不加验证地接受的某种关于主人的理论,以为自己真是国家的主人,至少也是主人的接班人。后来我保持了这种自我期许,则是因为西方经济学关于公共服务的道理讲得透彻,从中我看到了理想社会的逻辑。按照这种逻辑,假如我真想成为宪法意义上完整的公民,我就不能妄想只享受公民的权利而不理睬公民的义务。这两种关于主人的理论,一个来自过去,一个来自未来,都不是现实的产物。 从这个意义上说,民主制度的真正实行,也是提高公德水平的一个重要的前提条件。因为公德无非是主人翁的道德,不是主人翁,继续当臣民甚至奴才,这道德便没了根基 。 把上边提到的比喻再发挥一步:如果我雇小时工或者保姆来家打扫卫生,没想到他反客为主,仗着自己膀大腰圆在我家里当上了主子,这时我会作何反应?我被迫出去挣钱养家糊口,被迫给他发工资,这完全是因为没别的办法,不这样就会挨揍。那我还会在乎穿着雨靴踩地毯么?只要这室内卫生的事情还归那位当上了就不肯下台的小时工管,我才不在乎他忙不忙呢。累死他才好,累跑他更好。我怎么会体谅他的辛苦?他是猫,我是老鼠,我体谅猫的心情干什么?以皇帝为最高代表的统治者,就是这样的公仆。公仆如此德行,我的公德应该是什么样子? 三 大约2000年前,王充在《论衡》中谈论人性问题,说尧和舜当政的时候,百姓没有狂和愚的人。他还讲到一个古代的传说,尧和舜时代的老百姓,可以“比屋而封“,而桀和纣时代的老百姓,挨着屋子杀掉也不冤。他说,圣主的老百姓和恶主的老百姓如此不同,根源在于“化“,而不在人性。(2) 按照这种说法,刁民乃是政府“化“出来的,是政府培养出来的,并非天性就刁。当然刁民反过来也能培养贪官。不过要改变这种恶性循环,下手之处当然在政府。这是王充的高见。 中国古人讲到尧舜,经常有一些理想化的赞美,但我还是相信王充讲的传说。尧舜时代是什么时代?那是中国的第一个王朝尚未建立的时代,尧和舜都是大家选出来的,每个人都是一个范围不大的熟人社会的成员,彼此几乎都知根知底,而每个人的行为都会影响别人对他的长期看法。人在这样的社会里生活,想不为自己的行为负责是根本不可能的。无论这行为是好是坏,恐怕都不那么容易归功于或归咎于首领或别的什么人。按照我们对原始社会的理解,这些人确实也可以称为贵族,在这样的社会里,“比屋而封“应该是可能的。 到了桀纣时代,人心就不行了,这也是有道理的。桀纣是主子,其他一概都是臣民或奴才。如果主子们像桀纣那样,连一点替天行道的遮掩都不讲,臣民的道德水平自然也应该坏得没遮拦。 但我对王充的说法有个疑问。刚才谈论尧舜的逻辑和生活常识都提醒我们,聚族而居或者在小村庄中生活的人,如果不出这个小圈子,其实是坏不到哪里去的,不然就要自作自受。而桀纣时代,血缘社会还没有解体,人们如何能坏到“比屋而诛“却不制造冤假错案的程度呢? 我估计,恐怕那些坏都坏在了“公德“领域,坏在与“公家“--王公之类的统治集团--及其掌管的“公务“的关系方面。而在“私德“的领域,在家族内部,在朋友邻居和乡亲之间,我们的祖先就未必落后,说不定还能领先世界呢。中华民族长期处于世界先进水平,大概就有这“私德“的一份功劳。私德好,社会管理成本低,生产者也能安心努力地干活。可是公德不好,先进就保不住,别人不打自己也要乱,早晚要大乱。 四 如今,我们的血缘社会和地缘社会都解体了,而西方所谓的“市民社会“又没有建立起来。满大街的人谁也不认识谁,想随地吐痰就吐,想干坏事就干,连丢脸都不用怕,只要能躲过警察就不必承担责任,就可以不遭报应。随着私德领域的缩小和公德领域的扩张,我们的优势没了,劣势却露馅了。中国社会陷人了历史性的危机。 这个危险期,至少自明朝起就露出了端倪:因果报应的说法深入人心,关帝庙遍地开花,关云长所代表的无血缘关系的兄弟义气成为我们民族的理想。这些东西都是药,如果我们看见一个人不断吃镇静药,自然可以推断他的神经或精神出了毛病。 这种危机似乎还在加重。负责维护公共秩序的政府,本来还有无道的权威支持,可以得到被统治者的认可,统治集团也容易无争议地团结在真命天子周围。现在孔家店被砸了,天道和天命没人信了,本来就很弱的公德领域又少了不受置疑的维护者,中华民族到了最危险的时刻。 从这个意义上看,我们现在和过去一样处于大病未愈的时期。如果说有区别的话,无非是试验了几种药,效果都不那么理想。天道的变种和替代品在一百多年的历史试验中先后丧失了权威,人们重建观念世界的努力一次又一次地失败。各种药物的疗效和副作用总叫人不满意。譬如毛泽东思想的猛药,治疗贪官污吏的一时效果不错,但我们在毛泽东时代买东西的时候却整天招人白眼,被那些售货员训来训去。工人农民干活也大规模地偷懒--这都是大家在社会分工中安身立命的领域,表现出来的竟是这副德行。 现在,经济发展了,售货员(国营商业还不敢保证)却不敢训斥我们了。这就是社会进步的成就。工人(国有企业的正式工例外)农民和售货员并没有接受更高强度的道德教育,干起活来却认真多了,尽管这认真精神也难免体现在制造和贩卖假货上。我想,这种进步所以能够取得,关键在于现实的报应机制。没有人愿意掏钱买售货员和服务员的训斥,于是老板就要招募懂礼貌的人,就要培训员工笑迎他们的衣食父母。不能约束自己就可能被市场竞争淘汰出局--除非这老板得到了国家特许的垄断地位,当了某个领域的老虎和霸王。 这里说的是经济领域。我想,市场竞争在总体的方向上应该有利于实现孔老夫子的“己所不欲,勿施于人“的理想,因为人们更愿意为包含了这种品德的产品和服务掏钱。 政治或者叫公共领域显然不那么乐观。如果像经济领域一样建立某种竞争机制,好服务得到选票,于是升官;坏服务丢掉选票,于是丢官甚至丢掉饭碗,我们在前边为不守公德辩护的理由就要站不住脚了。 当然社会生活不仅仅包含政治和经济这两个领域。我的一个在美国生活了多年的朋友告诉我,美国人很怕坏了自己的信誉。他们轻易不敢赖账,轻易不敢违反交通规则。我这位朋友在一个月之内曾经两次驾车超速,被警察叫了下来,登记了他的社会安全号码。不久,他的违规记录就遭到了报应。他接到了来自保险公司的通知,他的汽车保险费用从200元增加到400元。美国人的社会安全号码就好像中国的身份证号码,是惟一的,也是公民得到福利待遇的凭据。但是他如果赖账,如果在公共信用方面有了不良记录,任何跟他做生意的人都会查出这个记录。被他的不良行为害了的银行保险和交通管理之类的部门,自然也愿意登记这个记录。结果,假如你要在一个文明宁静的地方租一间房子,房主一定会要你的社会安全号码,要是你的品德和信用记录不好,就别想以正常价格租到这间房。我的这位朋友认为,这种精密的报应机制,就是美国社会公德水平比较高的根基。这套机制奖励公德,惩罚缺德者。 本来,我对发达国家的报应机制的叙述到此就结束了。写完后,我将这篇文章传给一位在英国的朋友看,她说我忽视了一个重要的方面,那就是公正高效的司法体系。征得她的同意,我把她的部分论述翻译过来充实本文: 法律和司法系统在维护西方的社会秩序方面起着非常重要的作用。比如,按照法律规定,如果谁超速驾驶或酒后开车,他就要冒吊销驾驶执照的风险。真值得冒这么大的风险吗?如果违反了法律规定,你至少在一年之内无权开车。假如你习惯了每天驾车上班,现在却不得不改乘公共汽车或者出租汽车了,这自然非常不便,而且要为日常交通花更多的钱。更多的麻烦还在后头:即使过一段时间拿回了驾照,你也不再是一个干净驾照的持有者了。那意味着你不是一个老板可以完全信任的人。在英国求职,你必须出示你的干净驾照,以证明你是一个守法的公民。 在这里,维护良好社会秩序的核心角色是法律,而不是道德原则。离开了法律对人们行为的规范,道德原则什么也不是,至少是苍白无力的 。 在西方社会,你可以在超级市场、地铁车站和加油站之类的地方违反规定,但是你不能不面对自己的行为引起的后果。几乎没人愿意去干那种违规的事情,拿自己的前程、职业、家庭生活等等冒险。我们听到过一个故事,有个中国留学生在超级市场偷拿东西,他立刻就被驱逐出境了。在我看来,绝大多数人都觉得违规是不值得的。就是这样。 说到司法的公正和高效,我们又回到了政治领域。这真是一个绕不开的下手之处 。 五 走出恶性循环的实际努力开始之后,自然还有不可替代的精神方面的工作。譬如我们要找到一种类似信仰的东西,一种操守的基础。儒家的基础已经被骂倒了,新的信念的基础在哪里呢? 我想,这基础其实就在我们的生活之中,无须到天堂和地狱中寻找。譬如造化的报应。前边已经说过了,我们现在正在遭受报应。而且这报应一点也不神秘。 我们的祖先一直说天道好还,报应不爽,希望善有善报,恶有恶报。其实造化把这报应的工作交给了人类自己,交给他们设计和建立的制度。如果这个社会倾听这种要求,在尊重个人的基础上建立了权利和义务平衡的制度,建立了恰当的责任追究制度和贡献奖励制度,报应的体制就建立了。如果这个社会不建立这样的制度,那么,这个社会就会遭到报应,它会被其他有着更合乎造化要求的制度的社会所淘汰,或者被它自己所破坏。我们中国的2000年王朝循环就是造化给予帝国制度的报应。 报应不仅落到了整个社会和制度的头上,也落到了每个人的头上。我们随地吐痰,我们不排队,我们遇到不道德的国际行径和国内行径都假装看不见。这些严重缺乏公德的行为遭到的报应还不清楚么?我们被人家看不起。我们自己的生活环境和健康环境下降,使得每个人都生活在一个他不喜欢的世界里,这就是报应。为了让自己生活得更有尊严,也更健康,更美好,究竟值得不值得约束一下随地吐痰之类的毛病呢?或者,请一些执法者来管这件事情,而每个中国人都要为他们的工作多掏一笔税金。花钱雇人强迫你,并且用侮辱惩罚的手段迫使你自己不吐痰,然后我们再掏更多的钱行贿,逃避处罚,这不是很愚蠢很可笑么?干吗不约束自己一点,非得获得如此愚蠢可笑的报应呢?造化的报应就是这样的东西,你愚蠢,它就还你一个愚蠢。你可笑,它就还你一个可笑。所有的行为都会计入收支账目,真是天网恢恢,疏而不漏。任何社会和个人都要为自己的失职付出代价,你自己逃避了这种代价,别人就要替你付。人人都能逃避这样的代价,那就要由这个允许逃避的社会和民族的整体付,变本加厉地付。我们的黑头发可以染,黑眼睛和黄皮肤却难以掩饰。 造化终究是令人敬畏的,是不容糊弄的。我们自己,我们中国,我们人类,都是这造化的一员,我们今天的行为必定要影响我们的未来和我们的命运。这造化并不仅仅是一个威慑者,它还是一个鼓励者,是一种宽广的、诗意的生活的基础--只要你对它有足够的理解和尊重。 中国现在是一个人们正在逃离的社会,这个社会和我们这些社会成员正在为过去和现在的背离造化而遭到报应 。我们接受报应,我们不抱怨,这一切都是我们应得的。同时我们要努力,为未来建立新的报应机制,合乎造化的体制,跳出恶性报应的轮回。 Post by lgx @ 14:49 Serv-U 中 OTP S/KEY MD5 的奇怪使用

2003-12-15 14:05 关于 OTP S/KEY 可以参考 rfc2289。 奇怪的是 Serv-U 把用户的 secure passphrase 也加密后保存了,而且这个加密应该是可逆的。我觉得根本不需要保存 passphrase (在 Serv-U中就是用户password)。在 Serv-U 中 OTP 初始化的 sequence number 是 999。Serv-U 完全可以先生成seed,然后计算 1000 次,然后保留计算结果就行。 据我测试,删除ini中保存的用户password后仍然可以成功登录。 保存这个password会带来风险。一旦 ini 文件泄漏,就会导致用户 passphrase 泄漏(假设可逆),从而 S/KEY 认证失去意义。 Post by lgx @ 14:05 刘咪最新照片

2003-12-14 18:58 Post by lgx @ 18:58 SecureCRT 中文支持很好

2003-12-12 17:14 就是吃内存太多。putty 吃内存很少,但是中文支持不好。可惜我 Windows 编程太差,不然一定要改出一个中文支持好的 putty。如果使用 UTF-8 编码,putty 对中文的支持也不错。 Post by lgx @ 17:14 解决一个Linux Kernel Module的bug

2003-12-12 17:08 Module 老是导致 kernel 出错。用 IDApro 反汇编module,根据 kernel fault 时打印的出错指令,定位到出错位置,再对照 module source,很容易找到出错行。 当然前提是出错代码在 module 里。 2.2.14 kernel 没有实现 stat64,lstat64 等函数,hook 时要注意。 Post by lgx @ 17:08 晚上LP给猫咪洗澡

2003-12-11 21:04 这家伙,从小到大洗无数次澡了,每次都使劲挣扎,不知道以后会不会乖乖洗澡。 Post by lgx @ 21:04 穷的没法活了

2003-12-09 18:41 没钱,没车,没房子啊!!! Post by lgx @ 18:41 备忘:实现端口转发

2003-12-09 11:15 n 久以前做过,现在做又 search 了好半天。 如果不想修改源地址,SNAT规则不需要。 insmod ip_tables.o insmod ip_conntrack.o insmod iptable_nat.o iptables -t nat -A PREROUTING -p tcp --dport 5800 -i eth0 -j DNAT --to forward_to iptables -t nat -A POSTROUTING -d forward_to -p tcp --dport 5800 -j SNAT --to me iptables -t nat -A PREROUTING -p tcp --dport 5900 -i eth0 -j DNAT --to forward_to iptables -t nat -A POSTROUTING -d forward_to -p tcp --dport 5900 -j SNAT --to me Post by lgx @ 11:15 OpenSSL: 椭圆曲线签名与校验 (ECDSA)

2003-12-08 12:44 /* 目录:

  1. 简介
  2. 生成 ECDSA 密钥对
  3. 签名
  4. 校验 / /
  5. 简介

对 PE 文件做 ECDSA 签名. 签名写入 PE 头部 DOS Stub代码后边. 使用的椭圆 曲线是 FIPS 186-2 中的 P-192. 签名长度不超过 56 字节,强度和 RSA 1024 相当. / / 2. 生成 ECDSA 密钥对 生成的私钥用 RC4 加密. 生成形式为 c 语言可用的形式. / #include <stdio.h> #include <openssl/crypto.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/x509.h> #include <openssl/ecdsa.h> #include <openssl/engine.h> #include <openssl/err.h> #include <openssl/rc4.h> #include <conio.h> #define MAXPASS 64 #define PRIVKEY "static unsigned char privkey[%d] = {" #define PUBKEY "static const unsigned char pubkey[%d] = {" #define ENDKEY "\n};\n" int main(int argc, char argv[]) { RC4_KEY rc4; EC_KEY *ecdsa; char passbuf[MAXPASS + 3] = {MAXPASS}; char *pass; byte buf[1024]; byte *pp; int i,len;

printf( "Input password: " ); pass = _cgets(passbuf); if (pass == '\0' || passbuf[1] == 0) { printf( "NULL password\n" ); return -1; } RAND_seed(passbuf, sizeof (passbuf)); if ( (ecdsa = EC_KEY_new()) == NULL) { printf( "EC_KEY_new\n" ); return 0; } if ((ecdsa->group = EC_GROUP_new_by_nid(NID_X9_62_prime192v1)) == NULL) { printf( "EC_GROUP_new_by_nid\n" ); goto err; } if (!EC_KEY_generate_key(ecdsa)) { printf( "EC_KEY_generate_key error\n" ); goto err; } /

  • 生成 RC4 加密的ECDSA私钥 */ pp = buf; len = i2d_ECPrivateKey(ecdsa,&pp); if (!len) { goto err; }

RC4_set_key(&rc4,strlen(pass),(byte*)pass); RC4(&rc4,len,buf,buf);

printf(PRIVKEY,len); for (i=0; i<len; i++) { if ( !(i % 8) ) printf( "\n" ); printf( "0x%02X , " ,buf[i]); } printf(ENDKEY); /*

  • 生成ECDSA公钥 / pp = buf; len = ECPublicKey_get_octet_string(ecdsa,&pp); if (!len) { goto err; } printf(PUBKEY,len); for (i=0; i<len; i++) { if ( !(i % 8) ) printf( "\n" ); printf( "0x%02X , " ,buf[i]); } printf(ENDKEY); err: EC_KEY_free(ecdsa); return 0; } /
  1. 签名

签名时需要输入私钥密码 (最长 512 位). / #include <openssl/crypto.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/x509.h> #include <openssl/ecdsa.h> #include <openssl/engine.h> #include <openssl/err.h> #include <openssl/sha.h> #include <openssl/rc4.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <io.h> #include <windows.h> #include <commdlg.h> #include "resource.h" typedef unsigned char byte; #define MAXSIGLEN 128 #define MAXPASS 64 #define MAGIC_CHAR 0x27 static char password[MAXPASS]; static RC4_KEY key; /

  • RC4 加密过的ECDSA私钥 () */ static unsigned char privkey[] = { 0xBE , 0x5E , 0x1D , 0x8F , 0x79 , 0xBA , 0xC7 , 0x2B , 0x32 , 0x9D , 0x4A , 0xFC , 0xE7 , 0x62 , 0x24 , 0x8C , 0x84 , 0x88 , 0x32 , 0x6F , 0x4C , 0x5B , 0x32 , 0xEA , 0x46 , 0x97 , 0x71 , 0x83 , 0x84 , 0x3D , 0x91 , 0x79 , 0x4D , 0x17 , 0xB1 , 0x28 , 0xED , 0x39 , 0xBF , 0xDF , 0xDD , 0xF2 , 0x93 , 0x88 , 0xBF , 0xFD , 0x4D , 0x02 , 0xC7 , 0x1A , 0x22 , 0xAB , 0x41 , 0x41 , 0x9F , 0x63 , 0x26 , 0x7E , 0x49 , 0x08 , 0x7F , 0xB0 , 0xE3 , 0xB9 , 0xDB , 0xC4 , 0x04 , 0xE9 , 0x01 , 0xB8 , 0xC1 , 0x71 , 0x93 , 0xC6 , 0xD4 , 0x83 , 0xB3 , 0x08 , 0x28 , 0x18 , 0xE1 , 0x4C , 0xE1 , 0xD7 , 0x0C , 0x66 , 0x77 , 0x3E , 0x65 , 0x2F , 0x12 , 0xD3 , 0x2F , 0xD4 , 0xC3 , 0xB4 , 0x99 , 0xA2 , 0xF5 , 0x57 , 0x59 , 0xA1 , 0x20 , 0x81 , 0xEB , 0x3F , 0xCF , 0x46 , 0xD2 , 0x45 , 0x71 , 0x06 , 0x9C , 0x5F , 0x60 , 0x2E , 0x68 , 0xFB , 0x6C , 0xA4 , 0xC8 , 0x94 , 0x72 , 0xA3 , 0x3B , 0xE0 , 0x10 , 0xB9 , 0x1B , 0xAE , 0xFE , 0xD4 , 0x58 , 0x1C , 0xA9 , 0x80 , 0x0F , 0xF0 , 0x55 , 0xDC , 0xC6 , 0x58 , 0xE0 , 0x5D , 0x83 , 0xBB , 0x27 , 0x82 , 0x7E , 0xA1 , 0xF5 , 0x10 , 0x2E , 0x18 , 0x9A , 0xDA , 0x61 , 0x3B , 0xD2 , 0xA2 , 0xAB , 0x45 , 0x63 , 0xBD , 0x89 , 0xAD , 0xFB , 0x4E , 0x2E , 0x6D , 0x23 , 0x4A , 0x55 , 0x57 , 0x28 , 0x1A , 0xE5 , 0x5B , 0xC3 , 0x62 , 0x3B , 0x6F , 0xA5 , 0x96 , 0x72 , 0xBD , 0x16 , 0x36 , 0xC4 , 0xB9 , 0x2B , 0x31 , 0xE6 , 0x3B , 0x78 , 0xF0 , 0x2C , 0xBE , 0x4A , 0x70 , 0xA0 , 0xA1 , 0x5E , 0x38 , 0x4A , 0x3F , 0xFE , 0x79 , 0xD4 , 0xCF , 0x0C , 0x70 , 0x1B , 0xD5 , 0xE5 , 0x54 , 0x52 , 0x44 , 0x1A , 0x47 , 0xFD , 0x59 , 0x81 , 0xBF , 0xAE , 0x0C , 0xF4 , 0xDB , 0xC2 , 0x19 , 0xAC , 0xA9 , 0x2F , 0x90 , 0x31 , 0xEC , 0xEA , 0xDD , 0xCE , 0x5F , 0xA8 , 0xA7 , 0xEE , 0x79 , 0x1C , 0x20 , 0x95 , 0x93 , 0x22 , 0x61 , 0xA2 , 0x41 , 0x40 , 0xCF , 0x26 , 0xF4 , 0x73 , 0xFE , 0xD8 , 0x23 , 0x12 , 0x81 , 0x42 , 0x6D , 0x32 , 0xC2 , 0xD0 , 0x64 , 0xF2 , 0x02 , 0x0A , 0x22 , 0xFE , 0x20 , 0xB3 , 0x25 , 0x29 , 0x7B , 0x78 , 0xFA , 0x0D , 0x9B , 0x95 , 0x61 , 0xF5 , 0x40 , 0x1B , 0x43 , 0xEC , 0x7D , 0xEB , 0x61 , };

static const unsigned char dos[] = { 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x69, 0x50, 0x42, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x2E, 0x20, 0x0D, 0x0D, 0x0A, 0x24, MAGIC_CHAR, }; /*

  • ECDSA 签名 */ static unsigned int sign(byte *sig,const byte *buf,int len) { unsigned int siglen = MAXSIGLEN; EC_KEY *ecdsa = NULL; unsigned char pp = (unsigned char)privkey;

RAND_seed(buf, len); /*

  • 解密私钥 / RC4(&key, sizeof (privkey),privkey,privkey); ecdsa = d2i_ECPrivateKey(&ecdsa, (const unsigned char*)&pp, sizeof (privkey)); ZeroMemory(privkey, sizeof (privkey)); if ( ecdsa == NULL) { MessageBox(NULL, "Can't restore private key" , "Sign" ,MB_ICONERROR); return 0; } if (!ECDSA_sign(0,buf, len, sig,&siglen,ecdsa)) { MessageBox(NULL, "Sign error" , "Sign" ,MB_ICONERROR); EC_KEY_free(ecdsa); return 0; }

EC_KEY_free(ecdsa); return siglen; } static BOOL GetFileName(char *sFile) { OPENFILENAME ofn;

ZeroMemory(&ofn, sizeof (ofn));

ofn.lStructSize = sizeof (ofn); ofn.lpstrFile = sFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = "EXE/DLL/OCX files\0*.exe;.dll;.ocx\0All\0*.*\0" ; ofn.lpstrTitle = TEXT( "Please Select a File to sign" ); ofn.lpstrInitialDir = "." ; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_HIDEREADONLY; return GetOpenFileName(&ofn); } INT_PTR CALLBACK DlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_INITDIALOG) { SetFocus(GetDlgItem(hwndDlg,IDC_PASSWORD)); } else if (uMsg == WM_COMMAND) { if ( wParam == IDOK) { GetDlgItemText(hwndDlg,IDC_PASSWORD,password,MAXPASS); if (password[0] == '\0') { MessageBeep(MB_ICONASTERISK); SetFocus(GetDlgItem(hwndDlg,IDC_PASSWORD)); return TRUE; } else { EndDialog(hwndDlg,0); } } } else if ( uMsg == WM_CLOSE ) { EndDialog(hwndDlg,0); } return 0; }

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int len; byte sig[MAXSIGLEN]; unsigned int siglen; int fd; byte md[SHA_DIGEST_LENGTH]; char buf[1024]; SHA_CTX ctx; char sFile[MAX_PATH] = {0}; /*

  • 得到要签名的文件名 / if (!GetFileName(sFile)) { return -1; } if ((fd = open(sFile,O_RDWR | O_BINARY)) < 0) { MessageBox(NULL, "Can't open file for read-write" , "Open" ,MB_ICONERROR); return -1; } /
  • 检验文件 */ if ( (len = read(fd,buf,0x40)) != 0x40 ) { MessageBox(NULL, "Read error" , "Read" ,MB_ICONSTOP); goto out; } if (buf[0] != 'M' || buf[1] != 'Z') { MessageBox(NULL, "Not a valid PE file!" , "Sign" ,MB_ICONSTOP); goto out; } if ( *(unsigned int )(buf + 0x3C) < 0xA0) { MessageBox(NULL, "No enough file space to write signature" , "Sign" ,MB_ICONSTOP); goto out; } /
  • 计算 SHA1 */ SHA1_Init(&ctx);

SHA1_Update(&ctx,buf,len);

lseek(fd,0xA0L,SEEK_SET); while ( (len = read(fd,buf, sizeof (buf))) > 0) { SHA1_Update(&ctx,buf,len); } if (len == -1) { MessageBox(NULL, "Read error" , "Error" ,MB_ICONERROR); goto out; }

ZeroMemory(md, sizeof (md)); SHA1_Final(md,&ctx); /*

  • 输入解密口令 / ZeroMemory(password,MAXPASS); DialogBox(hInstance,MAKEINTRESOURCE(IDD_PASSWORD),NULL,(DLGPROC)DlgProc); if (password[0] == '\0') { MessageBox(NULL, "You must input password!" , "Error" ,MB_ICONSTOP); goto out; } RC4_set_key(&key,strlen(password),(const byte)password); ZeroMemory(password,MAXPASS); /*
  • ECDSA sign / { siglen = sign(sig,md,SHA_DIGEST_LENGTH); if (siglen) { /
  • Write / lseek(fd,0x40L,SEEK_SET); write(fd,dos, sizeof (dos)); write(fd,(byte)&siglen,1); write(fd,sig,siglen); MessageBox(NULL, "File signed" , "Ok" ,MB_OK); } } out: close(fd); return 0; } /*
  1. 校验

校验不需要输入密码. / #include <openssl/crypto.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/x509.h> #include <openssl/ecdsa.h> #include <openssl/engine.h> #include <openssl/err.h> #include <openssl/sha.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <io.h> #include <windows.h> #include <commdlg.h> typedef unsigned char byte; #define MAXSIGLEN 64 #define MAGIC_CHAR 0x27 /

  • ECDSA 公钥 / static const unsigned char pubkey[] = { 0x04 , 0xDA , 0x4C , 0x77 , 0xEB , 0x7A , 0x8C , 0x12 , 0x87 , 0xF3 , 0x6C , 0x10 , 0x87 , 0xA1 , 0xB1 , 0x2D , 0x96 , 0xE6 , 0x85 , 0xE0 , 0x40 , 0xD0 , 0x19 , 0x14 , 0xE3 , 0x1F , 0xF0 , 0x1A , 0x76 , 0x8D , 0x3A , 0x5D , 0x57 , 0x33 , 0xE6 , 0xD5 , 0x5D , 0x23 , 0x75 , 0x1E , 0x54 , 0x60 , 0x67 , 0xC9 , 0xA9 , 0x60 , 0x74 , 0xC5 , 0x3F , }; /
  • DOS stub 代码 / static const unsigned char dos[] = { 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x69, 0x50, 0x42, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x2E, 0x20, 0x0D, 0x0D, 0x0A, 0x24, MAGIC_CHAR, }; /
  • 校验 ECDSA 签名 */ static int verify(const byte *sig,int siglen,const byte *buf,int buflen) { int ret; EC_KEY *pub = NULL; byte pp = (byte)pubkey; if ( (pub = EC_KEY_new()) == NULL) { return 0; } if ((pub->group = EC_GROUP_new_by_nid(NID_X9_62_prime192v1)) == NULL) { EC_KEY_free(pub); return 0; }

pub = ECPublicKey_set_octet_string(&pub,(const byte**)&pp, sizeof (pubkey)); if (pub == NULL) { EC_KEY_free(pub); return 0; }

ret = ECDSA_verify(0,(const byte*)buf, buflen, sig, siglen,pub); EC_KEY_free(pub); return ret == 1 ? 1 : 0; } static BOOL GetFileName(char *sFile) { OPENFILENAME ofn;

ZeroMemory(&ofn, sizeof (ofn));

ofn.lStructSize = sizeof (ofn); ofn.lpstrFile = sFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = "EXE/DLL/OCX files\0*.exe;.dll;.ocx\0All\0*.*\0" ; ofn.lpstrTitle = TEXT( "Please Select a File to verify" ); ofn.lpstrInitialDir = "." ; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_READONLY; return GetOpenFileName(&ofn); }

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int len; byte sig[MAXSIGLEN]; unsigned int siglen = 0xFF; int fd; byte md[SHA_DIGEST_LENGTH]; char buf[1024]; SHA_CTX ctx; char sFile[MAX_PATH] = {0}; if (!GetFileName(sFile)) { return -1; } if ((fd = open(sFile,O_RDONLY | O_BINARY)) < 0) { MessageBox(NULL, "Can't open file for read" , "Open" ,MB_ICONERROR); return -1; } /*

  • 读入签名并检查 / lseek(fd,0x40L,SEEK_SET); if ( (len = read(fd,buf,0x60)) != 0x60) { MessageBox(NULL, "Read error" , "Read" ,MB_ICONSTOP); close(fd); return -1; } if (memcmp(buf,dos, sizeof (dos)) || (byte)buf[ sizeof (dos) - 1] != MAGIC_CHAR || buf[ sizeof (dos)] > MAXSIGLEN) { MessageBox(NULL, "Not signed or incorrect!" , "Verify" ,MB_ICONSTOP); close(fd); return -1; } siglen = buf[ sizeof (dos)]; memcpy(sig,buf + sizeof (dos) + 1,siglen); /
  • 计算 SHA1 */ SHA1_Init(&ctx);

lseek(fd,0L,SEEK_SET); if ( (len = read(fd,buf,0x40)) != 0x40) { MessageBox(NULL, "Read error" , "Read" ,MB_ICONSTOP); close(fd); return -1; } SHA1_Update(&ctx,buf,len); lseek(fd,0xA0L,SEEK_SET); while ( (len = read(fd,buf, sizeof (buf))) > 0) { SHA1_Update(&ctx,buf,len); } if (len == -1) { MessageBox(NULL, "Read error" , "Error" ,MB_ICONERROR); close(fd); return -1; }

close(fd);

memset(md,0, sizeof (md)); SHA1_Final(md,&ctx); if ( verify(sig,siglen,md,SHA_DIGEST_LENGTH) ) MessageBox(NULL, "Verify Ok!" , "Verify" ,MB_OK); else MessageBox(NULL, "Verify Error!" , "Verify" ,MB_ICONERROR); return 0; } Post by lgx @ 12:44 OpenSSL: 密钥交换,传输加密,挑战应答认证 (crypt.c)

2003-12-08 12:39 #include <stdio.h> #include <openssl/rand.h> #include <openssl/rc4.h> #include <openssl/md5.h> #include <openssl/evp.h> #include <openssl/hmac.h> #include "crypt.h" #define DEBUG #ifdef DEBUG #ifdef _WIN32 #define DBG #else #define DBG(fmts,args...) do { fprintf(stderr,fmts,##args); } while(0) #endif #else #define DBG #endif #ifdef DEBUG static char *hexstr(unsigned char *buf,int len) { const char *set = "0123456789ABCDEF" ; static char str[1024],*tmp; unsigned char *end; if (len > 1024) len = 1024;

end = buf + len; tmp = &str[0]; while (buf < end) { *tmp++ = set[ (*buf) >> 4 ]; *tmp++ = set[ (*buf) & 0xF ]; buf ++; } *tmp = '\0'; return str; } #endif static DH *get_dh4096(void) { static unsigned char dh4096_p[] = { 0xFA,0x14,0x72,0x52,0xC1,0x4D,0xE1,0x5A,0x49,0xD4,0xEF,0x09, 0x2D,0xC0,0xA8,0xFD,0x55,0xAB,0xD7,0xD9,0x37,0x04,0x28,0x09, 0xE2,0xE9,0x3E,0x77,0xE2,0xA1,0x7A,0x18,0xDD,0x46,0xA3,0x43, 0x37,0x23,0x90,0x97,0xF3,0x0E,0xC9,0x03,0x50,0x7D,0x65,0xCF, 0x78,0x62,0xA6,0x3A,0x62,0x22,0x83,0xA1,0x2F,0xFE,0x79,0xBA, 0x35,0xFF,0x59,0xD8,0x1D,0x61,0xDD,0x1E,0x21,0x13,0x17,0xFE, 0xCD,0x38,0x87,0x9E,0xF5,0x4F,0x79,0x10,0x61,0x8D,0xD4,0x22, 0xF3,0x5A,0xED,0x5D,0xEA,0x21,0xE9,0x33,0x6B,0x48,0x12,0x0A, 0x20,0x77,0xD4,0x25,0x60,0x61,0xDE,0xF6,0xB4,0x4F,0x1C,0x63, 0x40,0x8B,0x3A,0x21,0x93,0x8B,0x79,0x53,0x51,0x2C,0xCA,0xB3, 0x7B,0x29,0x56,0xA8,0xC7,0xF8,0xF4,0x7B,0x08,0x5E,0xA6,0xDC, 0xA2,0x45,0x12,0x56,0xDD,0x41,0x92,0xF2,0xDD,0x5B,0x8F,0x23, 0xF0,0xF3,0xEF,0xE4,0x3B,0x0A,0x44,0xDD,0xED,0x96,0x84,0xF1, 0xA8,0x32,0x46,0xA3,0xDB,0x4A,0xBE,0x3D,0x45,0xBA,0x4E,0xF8, 0x03,0xE5,0xDD,0x6B,0x59,0x0D,0x84,0x1E,0xCA,0x16,0x5A,0x8C, 0xC8,0xDF,0x7C,0x54,0x44,0xC4,0x27,0xA7,0x3B,0x2A,0x97,0xCE, 0xA3,0x7D,0x26,0x9C,0xAD,0xF4,0xC2,0xAC,0x37,0x4B,0xC3,0xAD, 0x68,0x84,0x7F,0x99,0xA6,0x17,0xEF,0x6B,0x46,0x3A,0x7A,0x36, 0x7A,0x11,0x43,0x92,0xAD,0xE9,0x9C,0xFB,0x44,0x6C,0x3D,0x82, 0x49,0xCC,0x5C,0x6A,0x52,0x42,0xF8,0x42,0xFB,0x44,0xF9,0x39, 0x73,0xFB,0x60,0x79,0x3B,0xC2,0x9E,0x0B,0xDC,0xD4,0xA6,0x67, 0xF7,0x66,0x3F,0xFC,0x42,0x3B,0x1B,0xDB,0x4F,0x66,0xDC,0xA5, 0x8F,0x66,0xF9,0xEA,0xC1,0xED,0x31,0xFB,0x48,0xA1,0x82,0x7D, 0xF8,0xE0,0xCC,0xB1,0xC7,0x03,0xE4,0xF8,0xB3,0xFE,0xB7,0xA3, 0x13,0x73,0xA6,0x7B,0xC1,0x0E,0x39,0xC7,0x94,0x48,0x26,0x00, 0x85,0x79,0xFC,0x6F,0x7A,0xAF,0xC5,0x52,0x35,0x75,0xD7,0x75, 0xA4,0x40,0xFA,0x14,0x74,0x61,0x16,0xF2,0xEB,0x67,0x11,0x6F, 0x04,0x43,0x3D,0x11,0x14,0x4C,0xA7,0x94,0x2A,0x39,0xA1,0xC9, 0x90,0xCF,0x83,0xC6,0xFF,0x02,0x8F,0xA3,0x2A,0xAC,0x26,0xDF, 0x0B,0x8B,0xBE,0x64,0x4A,0xF1,0xA1,0xDC,0xEE,0xBA,0xC8,0x03, 0x82,0xF6,0x62,0x2C,0x5D,0xB6,0xBB,0x13,0x19,0x6E,0x86,0xC5, 0x5B,0x2B,0x5E,0x3A,0xF3,0xB3,0x28,0x6B,0x70,0x71,0x3A,0x8E, 0xFF,0x5C,0x15,0xE6,0x02,0xA4,0xCE,0xED,0x59,0x56,0xCC,0x15, 0x51,0x07,0x79,0x1A,0x0F,0x25,0x26,0x27,0x30,0xA9,0x15,0xB2, 0xC8,0xD4,0x5C,0xCC,0x30,0xE8,0x1B,0xD8,0xD5,0x0F,0x19,0xA8, 0x80,0xA4,0xC7,0x01,0xAA,0x8B,0xBA,0x53,0xBB,0x47,0xC2,0x1F, 0x6B,0x54,0xB0,0x17,0x60,0xED,0x79,0x21,0x95,0xB6,0x05,0x84, 0x37,0xC8,0x03,0xA4,0xDD,0xD1,0x06,0x69,0x8F,0x4C,0x39,0xE0, 0xC8,0x5D,0x83,0x1D,0xBE,0x6A,0x9A,0x99,0xF3,0x9F,0x0B,0x45, 0x29,0xD4,0xCB,0x29,0x66,0xEE,0x1E,0x7E,0x3D,0xD7,0x13,0x4E, 0xDB,0x90,0x90,0x58,0xCB,0x5E,0x9B,0xCD,0x2E,0x2B,0x0F,0xA9, 0x4E,0x78,0xAC,0x05,0x11,0x7F,0xE3,0x9E,0x27,0xD4,0x99,0xE1, 0xB9,0xBD,0x78,0xE1,0x84,0x41,0xA0,0xDF, }; static unsigned char dh4096_g[] = { 0x02, }; DH *dh; if ((dh=DH_new()) == NULL) { return (NULL); }

dh->p = BN_bin2bn(dh4096_p, sizeof (dh4096_p),NULL); dh->g = BN_bin2bn(dh4096_g, sizeof (dh4096_g),NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return (NULL); } return (dh); } /*

  • 测试 / static const char seeds = "afu guhr^73642897838&%#HGbwjkhuhrnbdfheur-=]p;'m po93i" ; /
  • 初始化随机数,DH,RC4参数等 */ int crypt_init(CRYPT_CTX *ctx) { if (ctx == NULL) { DBG( "crypt_init: ctx is NULL\n" ); return -1; } if (RAND_status() == 0) { RAND_seed(seeds,strlen(seeds)); } if (( ctx->dh = get_dh4096()) == NULL) { DBG( "crypt_init: get_dh4096 error\n" ); return -2; } if (( ctx->key = malloc( sizeof (RC4_KEY))) == NULL) { DBG( "crypt_init: malloc error\n" ); return -3; } memset(ctx->key,0, sizeof (RC4_KEY));

ctx->encipher = ctx->decipher = RC4; return 0; } /*

  • 内存释放 */ void crypt_exit(CRYPT_CTX ctx) { if (ctx->dh) { DH_free(ctx->dh); } if (ctx->key) { free(ctx->key); } } /
  • 生成 DH 密钥对。
  • @buf 存放生成的公钥,失败为 NULL
  • @ret 小于 0 失败,成功为公钥字节长度 */ int crypt_dh(CRYPT_CTX *ctx,uint8_t **buf) { if (DH_generate_key(ctx->dh) == 0) { DBG( "crypt_dh : DH_generate_key error\n" ); return -2; } if ((*buf = malloc(BN_num_bytes(ctx->dh->pub_key))) == NULL) { DBG( "crypt_dh : malloc error\n" ); return -3; } return BN_bn2bin(ctx->dh->pub_key,buf); } /
  • 完成 DH 密钥交换,设置 RC4 密钥
  • @buf 对端 DH 公钥
  • @len 公钥长度 */ int crypt_setkey(CRYPT_CTX *ctx,const uint8_t *buf,size_t len) { int keylen; uint8_t *key,*md; BIGNUM pubkey; if (buf == NULL || len > DH_size(ctx->dh)) { /
  • 公钥错误 / DBG( "crypt_setkey : buf == NULL or Invalid len\n" ); return -1; } if ((key = malloc(DH_size(ctx->dh))) == NULL) { /
  • Out of memory / DBG( "crypt_setkey : malloc error\n" ); return -2; } if ((pubkey = BN_bin2bn(buf,len,NULL)) == NULL) { /
  • 很少出错 / DBG( "crypt_setkey : BN_bin2bn error\n" ); free(key); return -3; } if ((keylen = DH_compute_key(key,pubkey,ctx->dh)) < 0) { /
  • 共享密钥计算错误 */ DBG( "crypt_setkey : DH_compute_key error\n" ); free(key); BN_free(pubkey); return -4; }

md = MD5(key,keylen,NULL); DBG( "key = [%s]\n" ,hexstr(md,16)); /*

  • 设置 RC4 密钥 */ RC4_set_key(ctx->key,16,md);

free(key); BN_free(pubkey); return 0; } /*

  • 加密函数,在发包前调用
  • @in 要加密的数据
  • @inlen 要加密数据长度
  • @out 存放输出的加密结果,可以是in。如果不是in,应该是
  • 至少 inlen 字节的缓冲区 */ void crypt_encrypt(CRYPT_CTX *ctx,uint8_t *out,const uint8_t *in,size_t inlen) { if (ctx == NULL || out == NULL || in == NULL || inlen == 0) { DBG( "crypt_encrypt: Invalid params\n" ); return ; }

ctx->encipher(ctx->key,inlen,in,out); } /*

  • 解密函数,在收包后调用
  • @in 要解密的数据
  • @inlen 要解密数据长度
  • @out 存放输出的解密结果,可以是in。如果不是in,应该是
  • 至少 inlen 字节的缓冲区 */ void crypt_decrypt(CRYPT_CTX *ctx,uint8_t *out,const uint8_t *in,size_t inlen) { if (ctx == NULL || out == NULL || in == NULL || inlen == 0) { DBG( "crypt_decrypt: Invalid params\n" ); return ; }

ctx->decipher(ctx->key,inlen,in,out); } /*

  • 服务端生成 Request 数据
  • 成功返回 0 / int crypt_request(uint8_t req[16]) { return !RAND_bytes(req, sizeof (req)); } /
  • 客户端生成 Response 数据
  • @pass 虚用户口令
  • @req 来自 Server 的挑战数据
  • @resp 计算出的响应数据
  • 返回 0 成功。 */ int crypt_login(uint8_t resp[16],const char *pass,const uint8_t req[16]) { int len = sizeof (resp); if (pass == NULL) { DBG( "crypt_login : pass is NULL\n" ); return -1; }

HMAC(EVP_md5(),pass,strlen(pass),req, sizeof (req),resp,&len); return 0; } /*

  • 服务端验证用户
  • @pass 用户口令明文
  • @resp 来自客户端的应答
  • 成功返回 0 */ int crypt_auth(const char *pass,const uint8_t req[16],const uint8_t resp[16]) { static uint8_t buf[16] = {0}; int len = sizeof (buf); if (pass == NULL) { DBG( "crypt_auth : pass is NULL\n" ); return -1; }

HMAC(EVP_md5(),pass,strlen(pass),req, sizeof (req),buf,&len);

DBG( "crypt_auth : pass = [%s]\n" ,pass); DBG( "crypt_auth : req = [%s]\n" ,hexstr((uint8_t*)req,16)); DBG( "crypt_auth : resp = [%s]\n" ,hexstr((uint8_t*)resp,16)); DBG( "crypt_auth : buf = [%s]\n" ,hexstr(buf,16)); return memcmp(resp,buf,16); } #ifdef DEBUG void test_auth(void) { const char *pass = "12345678" ; const char *server_pass = "12345679" ; const char *pass2; uint8_t req[16],resp[16];

fprintf(stderr, "\nTest Vitual User Authentication ...\n" ); /*

  • Server 先生成 req 数据 / crypt_request(req); fprintf(stderr, "Server Request = [%s]\n" ,hexstr(req,16)); /
  • Server 把 req 发给 Client,假设 Client 已经收到 / /
  • Client 计算 Response / crypt_login(resp,pass,req); fprintf(stderr, "Client Response = [%s]\n" ,hexstr(resp,16)); /
  • Client 把用户名,Response 发送给 Server
  • 报文格式自己协商制定
  • 假设 Server 已经收到 / /
  • Server 根据用户名从自己的口令文件中得到用户名对应
  • 的口令,这里假设已经得到为 pass2
  • XXX: 这里只认证虚用户,要求 Server 保存用户明文口令,
  • 系统用户的认证自己考虑实现。 / /
  • Server 认证用户 */ fprintf(stderr, "Test correct login process ...\n" ); pass2 = pass; if (!crypt_auth(pass2,req,resp)) { fprintf(stderr, "Auth OK\n" ); } else { fprintf(stderr, "Auth Error\n" ); }

fprintf(stderr, "Test incorrect login process ...\n" ); pass2 = server_pass; if (!crypt_auth(pass2,req,resp)) { fprintf(stderr, "Auth OK\n" ); } else { fprintf(stderr, "Auth Error\n" ); } } int main() { int clen,slen; uint8_t *cbuf,sbuf; CRYPT_CTX client,server; uint8_t plain[7] = {0x12,0x34,0x56,0x78,0xAB,0xCD,0xEF}; uint8_t plain2[7] = {0x03,0x14,0x15,0x92,0x06,0x53,0x57}; uint8_t cipher[7]; /

  • Client / crypt_init(&client); clen = crypt_dh(&client,&cbuf); fprintf(stderr, "[%d] : cbuf = %s\n" ,clen,hexstr(cbuf,clen)); /
  • Server / crypt_init(&server); slen = crypt_dh(&server,&sbuf); fprintf(stderr, "[%d] : sbuf = %s\n" ,slen,hexstr(sbuf,slen)); /
  • Client 把 cbuf 发送给 server
  • Server 把 sbuf 发送给 client
  • 这里假设已经收到 / fprintf(stderr, "Generating session key ...\n" ); crypt_setkey(&client,sbuf,slen); crypt_setkey(&server,cbuf,clen); /
  • 现在,client 和 server 已经协商了 RC4 128 位密钥
  • 进行加密,解密测试 / /
  • Client 加密要发送的数据 */ fprintf(stderr, "\nTest Client --> Server communication ...\n" ); fprintf(stderr, "plain text = [%s]\n" ,hexstr(plain, sizeof (plain)));

crypt_encrypt(&client,cipher,plain, sizeof (plain)); fprintf(stderr, "After client encrypt = [%s]\n" ,hexstr(cipher, sizeof (plain))); /*

  • 假设 Server 已经收到,测试解密 / crypt_decrypt(&server,cipher,cipher, sizeof (plain)); fprintf(stderr, "After server decrypt = [%s]\n" ,hexstr(cipher, sizeof (plain))); /
  • 测试 Server -> Client 通信 / fprintf(stderr, "\nTest Server --> Client communication ...\n" ); fprintf(stderr, "plain text = [%s]\n" ,hexstr(plain2, sizeof (plain2))); crypt_encrypt(&server,cipher,plain2, sizeof (plain2)); fprintf(stderr, "After server encrypt = [%s]\n" ,hexstr(cipher, sizeof (plain))); /
  • 假设 Client 已经收到,测试解密 */ crypt_decrypt(&client,cipher,cipher, sizeof (plain2)); fprintf(stderr, "After client decrypt = [%s]\n" ,hexstr(cipher, sizeof (plain)));

crypt_exit(&client); crypt_exit(&server);

free(cbuf); free(sbuf); /*

  • 测试用户认证 */ test_auth(); return 0; } #endif Post by lgx @ 12:39 OpenSSL: 密钥交换,传输加密,挑战应答认证 (crypt.h)

2003-12-08 12:37 #ifndef CRYPT_H #define CRYPT_H #include <openssl/dh.h> #ifdef _WIN32 typedef unsigned char uint8_t; #else #include <stdint.h> #endif typedef struct _CRYPT_CTX { DH *dh; void *key; void (*encipher)(void ,size_t,const uint8_t,uint8_t *); void (*decipher)(void ,size_t,const uint8_t,uint8_t *); } CRYPT_CTX; extern int crypt_init(CRYPT_CTX *ctx) ; extern void crypt_exit(CRYPT_CTX *ctx) ; extern int crypt_dh(CRYPT_CTX *ctx,uint8_t **buf) ; extern int crypt_setkey(CRYPT_CTX *ctx,const uint8_t *buf,size_t len) ; extern void crypt_encrypt(CRYPT_CTX *ctx,uint8_t *out,const uint8_t *in,size_t inlen) ; extern void crypt_decrypt(CRYPT_CTX *ctx,uint8_t *out,const uint8_t *in,size_t inlen) ; extern int crypt_request(uint8_t req[16]); extern int crypt_login(uint8_t resp[16],const char *pass,const uint8_t req[16]); extern int crypt_auth(const char *pass,const uint8_t req[16],const uint8_t resp[16]); #endif Post by lgx @ 12:37 OpenSSL: 消息摘要算法

2003-12-07 21:11 消息摘要算法 简单接口 简单接口使用一个函数调用就可以完成消息摘要计算,这些接口包括 MD2,MD4,MD5,MDC2,RIPEMD,SHA1,函数声明都一样。 以 MD5为例,函数声明为: unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char md); 其中 d 指向要计算消息摘要的数据,n 为数据长度,md 指向保存消息摘要的缓冲区。如果 md 不为 NULL,那么它的长度必须能够容纳计算出来的消息摘要。对MD5,这个长度至少是 MD5_DIGEST_LENGTH。如果 md 为 NULL,那么计算出来的消息摘要保存在一个静态数组里,函数返回指向这个数组的指针。 下面是一个使用MD()计算消息摘要的小程序: //ex1.cpp #include <stdio.h> #include <string.h> #include <openssl/md5.h> / * 返回一个字节数组的 16 进制字符串表示 */ static char *hexstr(unsigned char *buf,int len) { const char *set = "0123456789abcdef"; static char str[65],*tmp; unsigned char *end; if (len > 32) len = 32; end = buf + len; tmp = &str[0]; while (buf < end) { *tmp++ = set[ (*buf) >> 4 ]; *tmp++ = set[ (*buf) & 0xF ]; buf ++; } tmp = '\0'; return str; } int main(int argc, char argv[]) { char *buf = "Hello,OpenSSL\n"; unsigned char md; md = MD5((const unsigned char)buf,strlen(buf),NULL); printf("%s\n",hexstr(md,MD5_DIGEST_LENGTH)); return 0; } 这个程序计算出字符串 ”Hello,OpenSSL\n” 的消息摘要为 97aa490ee85f397134404f7bb524b587 。可以用 Unix 下的 md5sum 程序检验是否正确: [root@cat /root]# echo "Hello,OpenSSL" | md5sum 97aa490ee85f397134404f7bb524b587

可以看到结果一样。 其它算法的计算类似,只用替换源代码中的 md5 为相应的算法名即可。 标准接口 简单接口容易使用,但是它要求被摘要数据在时间和空间上都是连续的。要 计算不连续数据的摘要,就必须使用标准接口。事实上,简单接口也是通过调用标准接口工作的。 以MD5为例,标准接口包括如下函数: void MD5_Init(MD5_CTX *c); void MD5_Update(MD5_CTX *c,const void *data,unsigned long len); void MD5_Final(unsigned char *md, MD5_CTX c); MD5_Init初始化MD5_CTX结构,MD5_Update计算摘要,MD5_Final输出摘要值。 下面是使用标准接口的 ex1.cpp 程序(只有main函数不同): //ex2.cpp //包含的头文件,hexstr函数都和 ex1.cpp一样 int main(int argc, char argv[]) { char *buf = "Hello"; char *buf2 = ","; char buf3 = "OpenSSL\n"; unsigned char md[MD5_DIGEST_LENGTH]; MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx,buf,strlen(buf)); MD5_Update(&ctx,buf2,strlen(buf2)); MD5_Update(&ctx,buf3,strlen(buf3)); MD5_Final(md,&ctx); printf("%s\n",hexstr(md,MD5_DIGEST_LENGTH)); return 0; } 检验: E:\ssl\md5\ex2\Debug> ex2 97aa490ee85f397134404f7bb524b587 可以看出,和 ex1 和 md5sum 的结果一致。 EVP 接口 #include <stdio.h> #include <string.h> #include <openssl/evp.h> / * 返回一个字节数组的 16 进制字符串表示 */ static char *hexstr(unsigned char *buf,int len) { const char *set = "0123456789abcdef"; static char str[65],*tmp; unsigned char *end; if (len > 32) len = 32; end = buf + len; tmp = &str[0]; while (buf < end) { *tmp++ = set[ (*buf) >> 4 ]; *tmp++ = set[ (*buf) & 0xF ]; buf ++; } tmp = '\0'; return str; } int main(int argc, char argv[]) { char *buf = "Hello"; char *buf2 = ","; char *buf3 = "OpenSSL\n"; unsigned int mdlen; unsigned char md[EVP_MAX_MD_SIZE]; EVP_MD_CTX ctx; const EVP_MD type = EVP_md5(); OpenSSL_add_all_digests(); if (argc > 1) { type = EVP_get_digestbyname(argv[1]); if (type == NULL) { fprintf(stderr,"Use default : MD5\n"); type = EVP_md5(); } } EVP_DigestInit(&ctx,type); EVP_DigestUpdate(&ctx,buf,strlen(buf)); EVP_DigestUpdate(&ctx,buf2,strlen(buf2)); EVP_DigestUpdate(&ctx,buf3,strlen(buf3)); EVP_DigestFinal(&ctx,md,&mdlen); printf("%s\n",hexstr(md,mdlen)); return 0; } BIO 接口 BIO_f_md()返回消息摘要的BIO方法。任何经过一个消息摘要BIO的数据都 被自动摘要。 BIO_set_md设置一个消息摘要BIO所使用的摘要算法。 下面是使用BIO的MD5例子: #include <stdio.h> #include <string.h> #include <openssl/evp.h> #include <openssl/bio.h> / * 返回一个字节数组的 16 进制字符串表示 */ static char *hexstr(unsigned char *buf,int len) { const char *set = "0123456789abcdef"; static char str[65],*tmp; unsigned char *end; if (len > 32) len = 32; end = buf + len; tmp = &str[0]; while (buf < end) { *tmp++ = set[ (*buf) >> 4 ]; *tmp++ = set[ (*buf) & 0xF ]; buf ++; } tmp = '\0'; return str; } int main(int argc, char argv[]) { int len; const char *str = "Hello,OpenSSL\n"; BIO *bio_null,bio_md; unsigned char md[EVP_MAX_MD_SIZE]; bio_null = BIO_new(BIO_s_null()); bio_md = BIO_new(BIO_f_md()); BIO_set_md(bio_md,EVP_md5()); bio_md = BIO_push(bio_md,bio_null); BIO_write(bio_md,str,strlen(str)); BIO_flush(bio_md); len = BIO_gets(bio_md,(char)md,EVP_MAX_MD_SIZE); printf("%s\n",hexstr(md,len)); BIO_free_all(bio_md); return 0; } 检验结果为: 97aa490ee85f397134404f7bb524b587 ,与 md5sum 的结果相同。 注意消息摘要 BIO 比较特殊:数据经过这种 BIO 不被修改,只是摘要值保留在 BIO 中,需要用 BIO_gets 而不是 BIO_read 读取。 Post by lgx @ 21:11 好多照片

2003-12-07 20:58 不过都比较模糊。早就应该买个好DC了,没办法,支持一次日货。:( Post by lgx @ 20:58 一些照片

2003-12-07 20:44 猫咪小时候 Post by lgx @ 20:44 不读书的理由

2003-12-07 19:43 1。烂书太多,遍地都是。 2。偶尔碰到一本好书,读时感觉写的太好了,以后可能也会反复读很多遍。可是放下以后,总觉得一无所获。作者的思想还是作者的思想,我的还是我的。真是奇怪。 3。我总觉得,书无法给我最需要的答案。我的问题必须自己去体会和解决。 Post by lgx @ 19:43 也该有一篇了

2003-12-07 19:29 必须承认,我已经很久不读书了。印象中高中以前,读书兴趣很高,拿到什么读什么。可能是书比较缺乏。大学时,对计算机书兴趣很高,图书馆几乎读遍了。对其它类书兴趣不大。工作后书读的越来越少。可以说,高中以前读的书支持着我进入大学;而大学读的书支持着现在的工作。 那么是不是应该为将来的某个阶段再开始读书?该考虑考虑了。 Post by lgx @ 19:29 香山

2003-12-07 19:12 计划过 n 次去爬香山了,总是没去成。或者是懒,或者是因事耽搁,或者是怕冷。 北京的风,真是刺骨的冷。这周末礼拜六有客人,礼拜天LP生病,又没去成。等买了DC再去吧。 Post by lgx @ 19:12 可爱的猫咪

2003-12-07 00:00 今天送走客人,发现找不到猫咪了。没在她窝里睡觉。打开橱柜,看到她正蜷在洗菜的塑料圆篮子里睡觉。姿势特别搞笑。篮子很小,她居然能缩进去,盘成圈睡得呼呼呼。 Post by lgx @ 00:00 IDA signature 问题

2003-12-04 17:14 不同 compiler compile 出的 lib 文件 sigmake 出的 sig 是否一样呢? 非常怀疑不一样。 这样的话,如果没有lib文件,静态链接的文件怎么用 sig 识别呢? Post by lgx @ 17:14 又一天无声无息过去了

2003-12-04 16:54 日子过的真快。 Post by lgx @ 16:54 第一记

2003-12-03 21:22 不知道会不会一直记下去。 Post by lgx @ 21:22