ラベル Tech の投稿を表示しています。 すべての投稿を表示
ラベル Tech の投稿を表示しています。 すべての投稿を表示

2010年10月15日金曜日

ソフトウェア業界に関する主な動き

ソフトウェア業界に関する主な動き

1985
・ジャストシステム、日本語ワープロソフト「一太郎」発表
1986
・マイクロソフト日本法人設立
・(社)日本パーソナルコンピュータソフトウェア協会(JPSA)が発足
・ロータス・ディベロップメントジャパン、「1-2-3」発売
・東芝、ラップトップ型パソコン「J-3100」発表
1987
・ニフティ、パソコン通信「NIFTY-Serve」開始
・PC AT互換機の日本語対応規格AXをマイクロソフトやメーカーが共同発表
1988
・NEC、PC-9800シリーズ用「日本語Windows」発売
1989
・東芝、ノート型パソコン「DynaBook」発売
・NEC、ノート型パソコン「98NOTE」発売
・パソコン出荷、総額で1兆円突破
1990
・日本IBM、「DOS/V」発表
・通商産業省「コンピュータウィルス対策基準」を公表
1991
・バブル経済の崩壊
・ノベル、ネットワークOS「NetWare386」発売
・フィンランド・ヘルシンキ大学生のリーナス・トーバルズ氏が「Linux」を公開(海外)
1992
・インテル、「Pentium」発表(海外)
・IBM、ノート型パソコン新ブランド「ThinkPad」発表
1993
・マイクロソフト、「Windows3.1」を日本で発売
・ジャストシステム、「一太郎Ver.5 for Windows」発売
1994   
・マイクロソフト、「Windows NT 3.1」を日本で発売
・「NIFTY-Serve」「PC-VAN」がインターネットと接続
・スタンフォード大学でYahoo!がサービス開始(海外)
・シリコン・グラフィックス創業者のジム・クラーク氏がネットスケープ・コミュニケーションズ設立

1995
・ヤフー設立(海外)
・サン・マイクロシステムズ、「Java」発表(海外)
・通商産業省が「ソフトウェア管理ガイドライン」を公表
・アマゾン・ドットコム設立(海外)
・ネットオークションのイーベイ設立(海外)
・マイクロソフト、「Windows 95」発売
・ネットスケープとサン・マイクロシステムズが共同で「JavaScript」開発(海外)
・国内向けパソコン出荷、500万台を突破
1996   
・マイクロソフト、インテルなど「USB」規格を発表(海外)
・シャープ、「カラーザウルス」発売
・オラクル、ネットスケープ、IBM、アップル、サン・マイクロシステムズ、ネットワーク端末規格「NC」発表(海外)
・ジャストシステム、「一太郎7 for Windows 95」発売

1997   
・アップル、「Mac OS 8」発売
・NEC、PC98-NXシリーズでDOS/V機に参入
・JPSAなど電子・情報・通信関連6団体でPCコンシューマサポート連絡協議会(PC-SOS)を設立

1998
・マイクロソフト、「Windows 98」発売
・アップル、「iMac」発売
・グーグル設立(海外)
・国内インターネット利用者、1,000万人を突破
1999
・サン・マイクロシステムズ、「Jini」発表(海外)
・NTTドコモ、「iモード」サービス開始
・「情報通信機器の即時償却制度」(パソコン減税)実施
・政府と民間企業などが協力し、コンピュータ2000年問題(Y2K)の対策を徹底
2000
・コンピュータ2000年問題(Y2K)クリア
・マイクロソフト、「Windows 2000」発売
・東芝、初のBluetooth対応製品を発表
・グーグル、日本語サービスを開始
・アマゾン・ドットコム、日本進出
2001
・内閣のIT戦略本部、「e-Japan戦略」まとめる
・アップル、「Mac OS X」発売
・パソコンメーカーに、事業系PCの回収とリサイクルを義務付ける、リサイクル法が施行(3R)
・NTTドコモ、第三世代携帯電話「FOMA」の試験サービス開始
・ソフトバンクグループ、8MbpsのADSLサービス「Yahoo!BB」開始
・(社)電子情報技術産業協会(JEITA)、企業向けPCに環境ラベル制度導入
・東京電力と東京通信ネットワーク、FTTH試験サービス開始
・アップル、携帯音楽プレーヤー「iPod」発売(海外)
・マイクロソフト、「Windows XP」発売

2002    ・ヤフーBB、IP電話「BBフォン」開始
・プロバイダー責任法施行
・国内インターネット利用者、5,000万人を突破
2003    ・IT投資促進税制スタート
・警視庁、ネットワークセキュリティ情報を提供する専用サイト「@Police」開設
・個人情報保護法が成立
・関東・近畿・中京の3大広域圏で地上派デジタル放送がスタート
・経済産業省、ITスキル標準(ITSS)Ver1.1、研修ロードマップVer1.0を発表
・国内向けパソコン出荷、1,000万台を突破
2004
・総務省、公的個人認証サービス開始
・ソーシャル・ネットワーク・サービス「mixi」が開始
・経済産業省、Webページのアクセシビリティ基準をJISに追加
2005
・文書の電子保存を容認する「e-文書法」が施行
・個人情報保護法、全面施行
・国内インターネット利用者7,000万人を突破

<<pcsmarket20_graph.gif>> <<pcsmarket20_graph2.gif>>

ARM怎么入门

ARM怎么入门
http://forum.edc-cn.com/FORUM_POST_76_9134_0.HTM

我不是高手,仍然是菜鸟。 但是回想起自己当时的迷茫,特意写了这篇东西,当作给和我一样的兄弟姐妹的帮助吧。问这个问题的人多半不是已经工作的工程师,而是和我一样是学生,所以这篇笔记就把看家当成我一样的菜鸟,高手勿怪。以下问题常被问到,我就想到哪说到哪吧。

一 首先说说ARM的发展 可以用一片大好来形容,翻开各个公司的网站,招聘里面嵌入式占据了大半工程师职位。

广义的嵌入式无非几种:传统的什么51、AVR、PIC称做嵌入式微控制器;ARM是嵌入式微处理器;DSP;FPGA。 客观的讲,工作需求量上DSP的需求比ARM要多,而ARM和FPGA差不多。

DSP因为数字处理与通信领域的空前发展而火暴,小到MP3 射象头,大到我们军品里的控制器,应用面很广。 FPGA的兄弟一般做ANSIC(特殊芯片设计,好象是这么翻译的)。而ARM单纯说来并不比一个单片机强多少,但是它的独特就在于不断下降的价格和提升的性能。这完全依靠于ARM公司的战略,厉害!!很佩服他们的战略眼光!!

值得注意的是:在找工作中,企业(著名的,小的不算)对单纯的ARM硬件开发工程师并不比单片机重视,很少有大企业的职位里写"从事过ARM开发优先"。写的多的是什么?"嵌入式LINUX"到这相信大家看出来了吧,需要的是硬件中的软件。

二 ARM是硬件还是软件

很难说,ARM是硬件,LINUX是软件。ARM的硬件多半已经模块化了,像我这样把板子改成这样的就算动的多的了,这同样是ARM公司的战略,再次佩服。 实际中的LINUX的开发工作更多,更耗时。从这方面说ARM应该算是软件了。

在找工作中更是这样,举个例子,联想里和ARM最接近的是"BIOS工程师"是软件,MOTO里接近的是嵌入式LINUX工程师是软件。而其他很多公司把嵌入式产品开发归为硬件。所以,不要讨论这个,好好玩转自己的板子才是关键。实在不爽你就把自己叫"嵌入式开发工程师"

三 要不要买开发板

我的答案是"在你个人的学习方法",但是如果看家是需要看这笔记的水平,个人推荐还是买现成的。

1 买

买板子可以把注意力集中在软件开发上,软件开发(尤其是驱动)可以不必担心自己硬件上的问题,我就是以便调试一边写驱动和程序,每次写驱动前就要先确认硬件没问题。另外,买板子更省钱和时间,我自己做的板子,原理图PCB花了2周以上!制版又15天,回来以后焊接44B0 160个脚!那叫一个麻烦~~花了多少钱呢?2层板,制版费就300块!当然 我把接口都外引了,还做了个20X18的LCD背板,板子比较大。总体下来 元件+LCD屏+PCB=11XX块!够2410的了。再有就是买的资料相对来说比较全。

2 做

自己做可以更了解底层硬件,可以按照自己的要求加东西,比如我就加了GPS模块、 GPRS模块 、SD卡模块,扩了个IIC的35个键子的键盘、把LCD接口按照买的LCD改装了,可以用FPC线直接连接。做的很爽的。玩一把吗。

当然,你可以有策略的做,比如像我一样,把RAM和ROM,网络都保持和某现成的板子一样,这样他们的资料你就可以拿过来直接用,给自己留个退路。其他的如SD了 什么的自己做。都达到了~~就是费钱,费时间。 再有就是给做的朋友几点建议:尽量拿到现成的板子,尽量多搜集其他板子的全套资料。

四 要不要有51

AVR等单片机基础 有更好,但没有也无所谓。

两个月以前,我只是看别人做,耳濡目染~~,本科学过单片机,从来没做过。我们这的技术主干做AVR和51,我就跟他们调过C语言程序。你看出来了?我是个不折不扣的菜鸟吧?但是做这个之前我特意找了两本书,看了里面的例子和原理图,这很重要。例程里有汇编有C,都看懂了就OK,不用自己现写

五 开发都需要学习哪些软件

总结起来最主要的有以下几个吧

1 ADS调试用确切的说是ADS+AXD。

ADS里包含AXD。原来都用SDT后来ARM公司停止对SDT支持了,改支持ADS了,还是用ADS吧。有的人的程序发布的仍然是SDT版本的,但基本都可以找到相应ADS的,新人在这里不要发蒙。ADS是编译器,AXD是调试器。便宜成AXF以后再在ARM的RAM里调试。

2 PLASHPGM FLASH烧写的软件。

AXD在RAM里调试,掉电就没有了,方便程序修改。调试好的程序再下到FLASH里,上电直接运行。同类的软件还有很多,什么FLUTED了、FLSHP了都是,但FLASHPGM最好,要是有人还问FLASH不支持BIN格式文件的问题就要看我写的PLASHPGM使用了。

3 BANYANT调试代理

(不知道名对不,起这么个难记的,我一般都叫它"半羊"因为知道它那几天刚吃了烤羊)

调试代理就是用它帮你使用更简单的JTAG(便宜啊)来实现原本1K才卖的JTAG仿真器的大部分功能。JTAG调试原理看我另一篇笔记。简单的就可以把他理解为你自己做的JTAG的驱动就行了。调试代理还有很多种,什么H-JTAG了、ARM7了(不知道具体叫什么,就记得可执行文件叫ARM7.EXE)都是,BANYANT比较好。

需要注意的是,没种调试代理安装方法虽然都简单 但都不一样,需要看说明。而且AXD调试之前都要运行。省钱了,就别怕麻烦了。

4 ARM-ELF-TOOLS工具链

里面是UCLINUX开发用的工具比如ARM-ELF-GCC只类的。工具链就是把很多工具打包在一起发布的方便你开发的东西。具体安装方法看我另一篇笔记。另外如果你开发LINUX就要用ARM-LINUX-TOOLS,不一样,不通用。

5 U-BOOT

大名鼎鼎的BOOTLOADER生成工具,同类的好象还有VIVI(名字很暧昧~~)生成的BOOTLOADER烧到FLASH里,然后就可以用BOOTLOADER下载 烧写其他了有了BOOTLOADER才能下UCLINUX。BOOTLOADER就像电脑上的BIOS。当然UCOS的不用这个,用什么我不知道:)最新版本是1.1.4 具体使用方法看我另一篇笔记吧。

6 UCLINUX包

UCLINUX的源码包,不用多说了吧?建议大家用现成的先体会一下,然后再自己编译,裁剪。因为单独UCLINUX的编辑技术上比较简单,但涉及的方面还是比较广的。

7 VMWARE 老牌的虚拟机软件,在一个机器上虚拟出一个机器装LINUX(PC上用的),省得你来回开关机了。记得装VMWARE-TOOLS,安装方法在我另一篇笔记里。

六 有哪些书推荐

主要推荐三本书,有这3本再加网络就不用别的书了

1 嵌入式设计及linux驱动开发指南――基于ARM9处理器配套FS2410开发板,学起来比较快

2 ARM体系结构与编程(电子版太大,用QQ邮箱给我发邮件 313638714@qq.com)最重要的是体系结构,汇编部分介绍,看看吧,增加理论素质。

3 Linux 设备驱动 Edition 3

写在这里是强调它的重要。 其他的书没了几本,没看见好的,大家有看过的推荐吧。

七 选UCOS?UCLINUX?LINUX?VXWORKS?还是当单片机用

1 搞开发,工程设计,用UCOS,小巧,多进程,简单,体现了ARM7的精髓。

2 LINUX 正根的嵌入式系统,LINUX消费与通信领域用的比较多,但缺点是必须ARM9才能跑,ARM9的板子自己做就不行了,6层板太贵。买开发板1K达底吧。但是还是推荐选ARM9+LINUX

3 UCLINUX 算投机嵌入式系统:)ARM7上可以跑,由有LINUX近?,学好好可以比较方便的转向LINUX,像我一样的穷鬼用吧,呵呵

4 VXWORKS 学好后可以找到高薪工作,但工作机会本身并不比LINUX好找。

5 当单片机用不推荐,因为对于学习来说多进程的系统设计才是ARM7的玩头,至少你也要整个UCOS啊:)有朋友问我先学这个当基础不行吗?那当然可以~~但我当时就用了1周搞定,就是我先的ADS在RAM中调试的笔记。后来我清空FLASH用的小段程序还是当时写的LED闪烁程序呢。另外1周里其中还因为自己过于菜,没把OM设置好导致晶阵不阵哈哈。这个是必须做的,但一带而过。目标放的远一点。

八 学习要用多长时间

我从菜鸟到现在两个多月,中间被打扰数次。仍然搞定了PCB设计与制版,RAM调试,FLASH下载,UBOOT移植和下载UCLINUX(没剪裁,用现成的),LCD驱动。再次坦诚的说:我确实比较菜,说这些不是让大家羡慕,只是告诉你们"你们应该比这个更好" 我相信良好的态度+合适的方法+及时的总结=成绩

九 ARM都玩什么就几点

1 硬件设计

2 系统移植

3 驱动开发

4 应用开发

没了。

其中推荐把注意力放在后两个上,3有难度,4比较灵活,最重要的是都是找工作的砝码。

十 我用的什么板子

很多人问我这个问题,我特意写过一个的。再说一次吧。我是自己做的,RAM、ROM、8019等比较麻烦而当时的自己不理解的都按照龚俊的做的。保持其他不便的情况下做了如下改动。

1 加了串口通信的GPS模块、 GPRS模块一个UART0,一个UART1,当与要用超级终端时用跳线切换。

2 SD卡,和7843触摸屏同时挂在SPI总线上,因为SPI只能挂一个设备,同时还做了I/O模拟的准备,把两个设备又通过跳线挂在4个IO上。

3 扩了个IIC的35个键子的键盘用的7290,不占用CPU,最大支持6?个键子,只上了35个,其他留接口。

4 把LCD接口按照买的LCD改装了,可以用FPC线直接连接。所以改动虽然多,但真正很移植了,初期调试有关的并没动,就是为了现在不那么菜的时候做准备:)

十一 开发流程这里是我的开发流程

1 设计原理图(含WIGGLER的JTAG访真器)

2 设计PCB(含WIGGLER的JTAG访真器)

3 制版

4 焊接电压,确定电压没问题

5 焊接44B0+JTAG电路+WIGGLER的JTAG访真器+周边电路,用BANYANT+仿真器连接,BANYANT提示错误,但可以显示44B0编号,好象是0X0F0F0F0F只类的,说明44B0没问题

6 焊接晶体+RAM+ROM+周边电路,用BANYANT+仿真器连接,可以显示正确的44B0了

7 用BANYANT+仿真器连接,开AXD,在命令行窗口操作RAM,看可不可以修改,可以的话(用内存窗口看RAM地址)RAM就没问题可以用这个命令"setmem 0xc000000,0xffffffff,32" 我的RAM挂在BANK6上 所以地址是0XC000000,你要是改了就也得改。

8 用我写的《自己写了个C工程模板又写了个使用说明 》里的方法调试程序吧,写个简单的,我当时写个LED闪烁的。看好使不。

9 把程序按照《FLASH烧写总结 》里的烧到FLASH里,测试一下

10 按照《UBOOT 移植操作》移植UBOOT

11 按照《UCLINUX下载简单说明》下个UCLINUX

12 看看驱动开发的方法,自己写个驱动看看

13 还有很多事东西着你玩 呵呵

十二 关于JTAG访真器 JTAG访真器现在用的多是简板的,一个244那种,用的没什么不好。按照并口定义不同分几种,建议选WIFFLER定义的,因为支持的软件多。这个网上多的是,不多说了。值得提的是有的JTAG访真器原理图上有跳线用来使能复位信号,这个一般不跳上。就是不用复位信号,因为JTAG协议里本身也可以控制44B0复位。当然,板子上的复位信号跳线也不用跳。

十三 哪个公司的ARM 这个是问题比较简单。

1 ARM7

主要就几个公司的三星,PHILIP,ATMEL的三星的44B0 http://auction1.taobao.com/auction/0/item_detail-0db1-0c6cd914de5d47ce4a1e9d35eb891907.jhtml PHILIP有几款 21XX 22XX 23XX 24XX http://shop.embedu.cn/ (网页中间"搜索宝贝"关键字 PHILIPS) ATMEL的有比较便宜的AT91SAM7S32 和AT91SAM7S64 专为8位应用产品量身定做,价格很便宜好象《3刀吧。和PHILIP的21XX差不多,资料太少,项目中选还不错。

2 ARM9

这个玩2410和2440的多吧,现在2440还比较火啊 可以考虑买个了 http://auction1.taobao.com/auction/0/item_detail-0db1-e0598b79e6867ad297b5e45889d3f427.jhtml 但是2410就比较便宜了,作为学习来说反倒还不错,推荐整一个:)

http://auction1.taobao.com/auction/11-1111/item_detail-0db1-863a7553b5b3823e172521fd86a32d6d.jhtml 其实ARM9用的最多的领域应该是消费电子,比如手机PDA,而这上面用的多的应该是INTEL的和TI的吧。但是INTEL的TI的入门材料少,价格高,自己看情况定吧

[News][Software Market] 国内ソフトウェア市場に果実はもうないのか? IDCが市場規模予測を発表

国内ソフトウェア市場に果実はもうないのか? IDCが市場規模予測を発表
IDC Japanが発表した2009年の国内ソフトウェア市場規模は前年比成長率マイナス10.6%の2兆234億4500万円。5年ほど前の市場規模に縮小してしまった。

[西尾泰三,ITmedia]
2010年04月21日 14時56分 更新
http://www.itmedia.co.jp/enterprise/articles/1004/21/news057.html

 IDC Japanは4月21日、2009年の国内ソフトウェア市場規模と向こう5年間の予測を発表した。

 それによると、2009年の国内ソフトウェア市場は2兆234億4500万円、前年比成長率マイナス10.6%で、4〜5年前の市場規模に縮小していることが明らかとなった。

 大分類市場別に見ると、アプリケーション市場規模が7905億500万円(前年比成長率マイナス16.2%)、アプリケーション開発/デプロイメント市場が4347億5200万円(同マイナス6.7%)、システムインフラストラクチャ市場が7981億8800万円(同マイナス6.6%)と推定している。アプリケーション市場の落ち込みがひどい点について、オーサリンング&パブリッシングソフトウェア製品の不振、製造業のアプリケーション分野全般に対する投資控えが影響したと同社は分析している。

 2010年は若干回復するものの、2年連続でマイナス成長を遂げるとしており、前年比成長率でマイナス5.7%、市場規模で1兆9081億6900円と2兆円を割る数字を予測している。

 さらに、同市場の2009年から2014年までの年間平均成長率(CAGR)は0.6%であると予測している。このペースで推移した場合、2014年の国内ソフトウェア市場は2兆882億4600万円となる。これは2006年時点の市場規模(2兆850億600万円)を若干上回る程度の規模でしかない。つまり、同市場の景気は今後下がり続けることはないという程度に過ぎず、力強さはまったく見られない。

 まとめると、国内ソフトウェア市場は2008年をピークに、ポジティブな材料がないまま今後5年程度は低空飛行を続けるということになる。企業によっては収益構造の大幅な変革を迫られるところもありそうだ。

2010年10月13日水曜日

SQUID NTLM

SQUID
http://squid.sourceforge.net/ntlm/


NTLM - C and Java

NTLM挑战模式散列认证加密协议过程,算法实现与一些想法

http://www.cnblogs.com/huqingyu/archive/2008/02/17/1071634.html

创建时间:2003-05-28
文章提交:flashsky (flashsky1_at_sina.com)

NTLM挑战模式散列认证加密协议过程,算法实现与一些想法
转摘请注明作者和安全焦点
作者:FLASHSKY
SITE
WWW.XFOCUS.NETWWW.SHOPSKY.COM
邮件:flashsky@xfocus.org
作者单位:启明星辰积极防御实验室

说明:
本来先从看见小四的《LM/NTLM验证机制》就没准备发的,但是从如下几点考虑还是发:
1。给出完全的算法实现代码
2。小四的关于NTLMLM的过程针对返回会话KEY的有效,针对完全挑战模式下说明并非完全
3。一些新的思路和思考
4。安全BLOB的结构说明

一:NTLM认证算法过程
    1。客户端申请挑战
     安全BLOB的结构如下:
    {
        CHAR DESC[8]="NTLMSSP";
        DWORD NO=1        //顺序号
        DWORD FLAG        
        WORD DOMAINNAMELEN    //域名长度
        WORD DOMAINNAMEMAXLEN//域名最大长度
        DWORD DOMAINNAMEOFFSET//域名便移
        WORD HOSTNAMELEN    //主机名长度
        WORD HOSTNAMEMAXLEN    //主机名最大长度
        DWORD HOSTNAMEOFFSET    //主机名便移
        CHAR HOSTNAME[HOSTNAMELEN]//主机名
        CHAR DOMAINNAME[DOMAINNAMELEN]//域名
    }
     2。服务器返回挑战,这个挑战是一个8字节的随机数    
     安全BLOB的结构如下:
    {
        CHAR DESC[8]="NTLMSSP";
        DWORD NO=2        //顺序号,必须为2
        WORD DOMAINNAMELEN    //帐户域名长度
        WORD DOMAINNAMEMAXLEN    //帐户域名最大长度
        DWORD DOMAINNAMEOFFSET////帐户域名偏移
        DWORD FLAG
        BYTE CHALLAGE[8]    //8字节挑战
        BYTE RE[8]        //保留8字节,必须为0
        WORD HOSTNAMELISTLEN  //主机名列表长度
        WORD HOSTNAMELISTMAXLEN//主机名列表最大长度
        DWORD HOSTNAMELISTOFFSET//主机名列表偏移
        CHAR DOMAINNAME[DOMAINNAMELEN]
        CHAR HOSTLISTNAME[HOSTNAMELISTLEN]
        //这里是多个结构组成
        //每个结构如下:
        //WORD ITEMNO;索引
        //WORD HOSTNAMELEN;主机名长度
        //BYTE HOSTNAME[HOSTNAMELEN]:主机名
    }
    3。客户端加密密码散列
    其实这个过程还是很复杂的
    如果是明文口令,先将此口令转化成散列,如果是系统用户则直接根据令牌从SESSION表中取出散列。
    这下面就是小四的文章中没提到的过程
    客户端先生成一个随机KEY,然后和服务器端的挑战使用MD5算法生成16字节的散列,但MS只取前8字节做为加密KEY,其实后面的散列加密并非是使用挑战直接加密的,而是
使用此加密KEY进行加密的。
        这个算法的代码如下:romkey就是客户端生成的一个随机KEYchallage就是服务器挑战
void challagetorkey(unsigned char * romkey,unsigned char * challage,unsigned char * enkey)
{
    unsigned char LM[0x58];
    md5init(LM);
    *(DWORD *)LM=0x200;
    memcpy(LM+0X18,challage,8);
    memcpy(LM+0X20,romkey,8);
    *(DWORD *)(LM+0x28)=0x80;
    *(DWORD *)(LM+0x50)=0x80;
    md5final(LM);
    memcpy(enkey,LM+8,8);
}
    然后再使用生成的加密KEY加密MD4生成的NTLM散列,具体的过程在下四的文章中有详细介绍,这里就不再讲了,后面给出了完全实现的代码。
    同时还会先选择一个RC4KEY,对MD4生成的NTLM散列用MD4再生成一个散列,再用HMACMD5算法,加密KEY,这个散列计算出一个0X10字节的散
列,用此散列和rc4_key函数生成rc4key表,最后用这个KEY表和先选择的RC4KEY生成一个0X10字节的RC的结果出来。
    但要注意的是:通常情况下,这个RC4的结果并没用于认证。

    安全BLOB的结构如下:
    {
        CHAR DESC[8]="NTLMSSP";
        DWORD NO=3        //顺序号,必须为3
        WORD RANDOMKEYLEN    //客户端随机KEY长度,固定为0X18
        WORD RANDOMKEYMAXLEN    //客户端随机KEY最大长度,固定为0X18
        //其实客户端随机KEY只有8字节,但是后面补0添满0X18字节
        DWORD RANDOMKEYOFFSET////客户端随机KEY偏移
        WORD ENNTLMLEN    //加密的NTLM散列长度,固定为0X18
        WORD ENNTLMMAXLEN    //加密的NTLM散列最大长度,固定为0X18
        DWORD ENNTLMOFFSET    //加密的NTLM散列偏移
        WORD HOSTNAMELEN  //主机名长度
        WORD HOSTNAMEMAXLEN//主机名最大长度
        DWORD HOSTNAMEOFFSET//主机名偏移
        WORD USERNAMELEN  //用户名长度
        WORD USERNAMEMAXLEN//用户名最大长度
        DWORD USERNAMEOFFSET//用户名偏移
        WORD USERDOMAINLEN  //帐户域名长度
        WORD USERDOMAINMAXLEN//帐户域名最大长度
        DWORD USERDOMAINOFFSET//帐户域名偏移
        WORD ENNTLMRC4LEN    //加密的RC4 NTLM散列长度,固定为0X10
        WORD ENNTLMRC4MAXLEN    //加密的RC4 NTLM散列最大长度,固定为0X10
        DWORD ENNTLMRC4OFFSET    //加密的RC4 NTLM散列偏移
        DWORD FLAG
        CHAR HOSTNAME[HOSTNAMELEN]//主机名
        CHAR USERNAME[HOSTNAMELEN]//用户名
        CHAR USERDOMAINNAME[HOSTNAMELEN]//帐户域名
        RANDOMKEY[0X18]//其实客户端随机KEY只有8字节,但是后面补0添满0X18字节
        ENNTLM[0X18]
        ENRC4NTLM[0X10]
    }
    
    4。服务器认证
      服务器获得客户端随即KEY以后,也和挑战运算获得此加密KEY,然后计算加密的NTLM散列做对比进行判断。

    5。一些思考
    主要是关于重放攻击的,其实真正的加密KEY是挑战和客户端随机KEYMD5运算的结果,那么如果我们嗅探出了一个挑战,随机KEY
能计算出加密KEY,如果我们发起一个请求获得一个挑战2,如果能计算一个随即KEY2(这个可由我们自己控制),满足MD5(挑战2,随即KEY2
=加密KEY,那么我们就能发送我们修探获得的安全BLOB中的加密散列的内容来获得认证。
        当然MD5的算法本事就是要防碰撞的,但是在MSSMB实现中,由于MD5生成的是16字节的散列,但是用来做加密KEY的只是前8个字节,那
么对于寻找只满足部分(前8字节)碰撞的算法复杂度就会大大的降低,当然我们在MD5中唯一能控制的东西就是随即KEY,但是挑战KEY已知,其实
针对加密算发是常量(因为加密内容固定为0X1O字节,其他的内容可以常量),应该来说还是很有希望的。不过就我的数学水平而已,尝试了
一下就被难到了,希望对MD5碰撞有研究的人给予指教。下面就是给出的一个针对其挑战,随即KEY到加密KEY的替代函数:

void challagetorkey(unsigned long c1,unsigned long c2,unsigned long r1,unsigned long r2)
{
//我们把挑战看做2unsigned long的数C1,C2,客户端随即KEY也看做2unsigned long的数R1,R2
//最后生成的是B1D1S1D2,但其实用做加密KEY的只是B1D1而已
//如果我们知道B1D1C1C2,是否能找过一个R1R2,使得满足这个函数呢?
//按照概率是针对每个B1D1都有可能找到对应的R1R2,因为MD5的算发要求是每个字节的变化都应该平均分布的
//我们可控的是2568次方,结果也是2568次方
//即使不是完全平均分布的,在测试100个挑战中总会有满足的吧?
//而算法复杂度对于16字节的25616次方应该降低了不少
//那么再退一步说,如果我们知道B1D1C1C2R1,如果能解出R2也行,我们对R1实行穷举
//R12564次方,4亿左右的穷举对现在的机器不应该是负担吧?当然真正实现工具由于认证要求,可能要求在10分钟以内
//但是如果我们在2天内能找到结果,也能说明很多问题
    DWORD a1,d1,d2,s1;
    DWORD b1;

    b1=(((0x10325476^0x98badcfe)&0xefcdab89)^0x10325476)+c1;
    b1=b1+0x67452301+0xd76aa478;
    b1=((b1<<0x7)|(b1>>0x19))+0xefcdab89;
    //第一轮
    a1=(((0x98badcfe^0xefcdab89)&b1)^0x98badcfe)+0xe8c7b756;
    d2=0x10325476+c2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    a1=(((0xefcdab89^b1)&d2)^0xefcdab89)+0x242070db;
    s1=0x98badcfe+r1+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    a1=(((d2^b1)&s1)^b1)+0xc1bdceee;
    d1=0xefcdab89+r2+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    a1=(((d2^s1)&d1)^d2)+0xf57c0faf;
    b1=b1+0x80+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    a1=(((s1^d1)&b1)^s1)+0x4787C62A;
    d2=d2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;    
    a1=(((d1^b1)&d2)^d1)+0xA8304613;
    s1=s1+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;    
    a1=(((d2^b1)&s1)^b1)+0xFD469501;
    d1=d1+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;    
    a1=(((d2^s1)&d1)^d2)+0x698098D8;
    b1=b1+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    a1=(((s1^d1)&b1)^s1)+0x8B44F7AF;
    d2=d2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    a1=(((d1^b1)&d2)^d1)+0xFFFF5BB1;
    s1=s1+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    a1=(((d2^b1)&s1)^b1)+0x895CD7BE;
    d1=d1+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    a1=(((d2^s1)&d1)^d2)+0x6B901122;
    b1=b1+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    a1=(((s1^d1)&b1)^s1)+0xFD987193;
    d2=d2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    a1=(((d1^b1)&d2)^d1)+0xA679438E;
    s1=s1+0x80+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    a1=(((d2^b1)&s1)^b1)+0x49B40821;
    d1=d1+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    //第二轮
    a1=(((s1^d1)&d2)^s1)+0xF61E2562;
    b1=b1+c2+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    a1=(((d1^b1)&s1)^d1)+0xC040B340;
    d2=d2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    a1=(((d2^b1)&d1)^b1)+0x265E5A51;
    s1=s1+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    a1=(((d2^s1)&b1)^d2)+0xE9B6C7AA;
    d1=d1+c1+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    a1=(((s1^d1)&d2)^s1)+0xD62F105D;
    b1=b1+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    a1=(((d1^b1)&s1)^d1)+0x2441453;
    d2=d2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    a1=(((d2^b1)&d1)^b1)+0xD8A1E681;
    s1=s1+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    a1=(((d2^s1)&b1)^d2)+0xE7D3FBC8;
    d1=d1+0x80+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    a1=(((s1^d1)&d2)^s1)+0x21E1CDE6;
    b1=b1+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    a1=(((d1^b1)&s1)^d1)+0xC33707D6;
    d2=d2+0x80+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    a1=(((d2^b1)&d1)^b1)+0xF4D50D87;
    s1=s1+r2+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    a1=(((d2^s1)&b1)^d2)+0x455A14ED;
    d1=d1+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    a1=(((s1^d1)&d2)^s1)+0xA9E3E905;
    b1=b1+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    a1=(((d1^b1)&s1)^d1)+0xFCEFA3F8;
    d2=d2+r1+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    a1=(((d2^b1)&d1)^b1)+0x676F02D9;
    s1=s1+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    a1=(((d2^s1)&b1)^d2)+0x8D2A4C8A;
    d1=d1+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    //第三轮
    a1=((d2^s1)^d1)+0xFFFA3942;
    b1=b1+a1;
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    a1=((s1^d1)^b1)+0x8771F681;
    d2=d2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    a1=(d2^d1)^b1;
    s1=s1+0x6D9D6122+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    a1=d2^s1;
    d1=d1+0x80+0xFDE5380C+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    b1=b1+c2+0xA4BEEA44+(d1^a1);
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    a1=((s1^d1)^b1)+0x4BDECFA9;
    d2=d2+0x80+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    a1=(d2^d1)^b1;
    s1=s1+0xF6BB4B60+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    a1=(d2^s1);
    d1=d1+0xBEBFBC70+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    b1=b1+0x289B7EC6+(d1^a1);
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    a1=((s1^d1)^b1)+0xEAA127FA;
    d2=d2+c1+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    a1=(d2^d1)^b1;
    s1=s1+r2+0xD4EF3085+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    a1=d2^s1;
    d1=d1+0x4881D05+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    a1=d1^a1;    
    b1=b1+a1+0xD9D4D039;
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    a1=((s1^d1)^b1)+0xE6DB99E5;
    d2=d2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    a1=((d2^d1)^b1);
    s1=s1+0x1FA27CF8+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    a1=((d2^s1)^b1);
    d1=d1+r1+0xC4AC5665+a1;
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    //4
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0xF4292244;
    b1=b1+c1+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0x432AFF97;
    d2=d2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xAB9423A7;
    s1=s1+0x80+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    a1=(((b1^0xFFFFFFFF)|s1)^d2);
    d1=d1+0xFC93A039+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0x655B59C3;
    b1=b1+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0x8F0CCC92;
    d2=d2+r2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xFFEFF47D;
    s1=s1+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0x85845DD1;
    d1=d1+c2+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0x6FA87E4F;
    b1=b1+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0xFE2CE6E0;
    d2=d2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xA3014314;
    s1=s1+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0x4E0811A1;
    d1=d1+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0xF7537E82;
    b1=b1+0x80+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0xBD3AF235;
    d2=d2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0x2AD7D2BB;
    s1=s1+r1+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0xEB86D391;
    d1=d1+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;

    b1=b1+0x67452301;
    d1=d1+0xefcdab89;
    s1=s1+0x98badcfe;
    d2=d2+0x10325476;
}


    6。实现代码的说明
这个代码是完全在TCP只上实现NTLM挑战认证的,密码的计算不调用任何加密的API
如果知道散列也可以去掉口令到散列的部分直接使用散列进行处理。

#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <wincrypt.h>
#include <process.h>
#include <string.h>
#include <winbase.h>
# include <wincrypt.h>
#define SECURITY_WIN32
# include <Security.h>
# include <Ntsecapi.h>
# include "smb.h"

void SmbNegotiate(SMBP * psmbp);
void SmbSessionSetupAndX1(SMBP * psmbp);
void SmbSessionSetupAndX2(SMBP * psmbp,wchar_t * username,wchar_t * domainname,wchar_t * password);
void deskey(char * LmPass,unsigned char * desecb);
void passtoowf(wchar_t * password,unsigned char * paswdowf);
void initLMP(char * pass,unsigned char * LM);
void deskey(char * LmPass,unsigned char * desecb);
void des(unsigned char * LM,char * magic,unsigned char * ecb,long no);
void md4init(unsigned char * LM);
void md4(unsigned char * LM);
void md5init(unsigned char * LM);
void md5final(unsigned char * LM);
void initMDP(PLSA_UNICODE_STRING pass,unsigned char * LM);
void hashtocread(unsigned char * enkey,unsigned char * hash,unsigned char * cread);
void challagetorkey(unsigned char * romkey,unsigned char * challage,unsigned char * enkey);
void hmacmd5(unsigned char * rc4key,unsigned char * enkey);
void rc4_key(unsigned char * rc4keylist,unsigned char * rc4key,int keylen);

typedef DWORD (CALLBACK* RTLUPCASEUNICODESTRINGTOOEMSTRING)(PLSA_UNICODE_STRING, PLSA_UNICODE_STRING, DWORD);
RTLUPCASEUNICODESTRINGTOOEMSTRING RtlUpcaseUnicodeStringToOemString;

typedef struct _SMBNBT
{
    unsigned char nbtsmb;
    unsigned char flag;
    short smbpacketlen;
}SMBNBT,* PSMBNBT;

typedef struct _SMBINFO
{
    unsigned char magic[4];
    BYTE smbtoken;
    BYTE errcodeclass;
    BYTE dosaherrcode;
    unsigned char errcode[2];
    BYTE flagsummary;
    short flagsummary2;
    short unuse[6];
    short treeid;
    short callprocessid;
    short userid;
    short multiplexid;
    unsigned char info[2048];
}SMBINFO,* PSMBINFO;

typedef struct _SMBP
{
    SMBNBT smbnbt;
    SMBINFO smbinfo;
}SMBP,* PSMBP;

wchar_t navos[]=L"windows 2000 2195";
wchar_t lanman[]=L"windows 2000 5.0";
unsigned char challage[8]={0x53,0xe6,0x97,0x53,0xfb,0x97,0x7c,0x19};
unsigned char romkey[8]={0xc7,0x91,0xdd,0xe8,0x5c,0xcd,0xc8,0xde};

unsigned char DESParity[]={0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
unsigned char DESDShift[]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,
0x64,0xCC,0xF9,0x29,0xDF,0xDE,0x86,0x4A,0x81,0x84,9,0x3C,0,0,0,0,
0xFB,0x99,0xE9,8,0xEC,0x87,0x67,0x2F,0x59,0x0FD,0x22,0xF1};

DWORD DESKEY1[]={
0x00000000,0x00000010,0x20000000,0x20000010,0x00010000,0x00010010,0x20010000,0x20010010,
0x00000800,0x00000810,0x20000800,0x20000810,0x00010800,0x00010810,0x20010800,0x20010810,
0x00000020,0x00000030,0x20000020,0x20000030,0x00010020,0x00010030,0x20010020,0x20010030,
0x00000820,0x00000830,0x20000820,0x20000830,0x00010820,0x00010830,0x20010820,0x20010830,
0x00080000,0x00080010,0x20080000,0x20080010,0x00090000,0x00090010,0x20090000,0x20090010,
0x00080800,0x00080810,0x20080800,0x20080810,0x00090800,0x00090810,0x20090800,0x20090810,
0x00080020,0x00080030,0x20080020,0x20080030,0x00090020,0x00090030,0x20090020,0x20090030,
0x00080820,0x00080830,0x20080820,0x20080830,0x00090820,0x00090830,0x20090820,0x20090830};

DWORD DESKEY2[]={
0x00000000,0x02000000,0x00002000,0x02002000,0x00200000,0x02200000,0x00202000,0x02202000,
0x00000004,0x02000004,0x00002004,0x02002004,0x00200004,0x02200004,0x00202004,0x02202004,
0x00000400,0x02000400,0x00002400,0x02002400,0x00200400,0x02200400,0x00202400,0x02202400,
0x00000404,0x02000404,0x00002404,0x02002404,0x00200404,0x02200404,0x00202404,0x02202404,
0x10000000,0x12000000,0x10002000,0x12002000,0x10200000,0x12200000,0x10202000,0x12202000,
0x10000004,0x12000004,0x10002004,0x12002004,0x10200004,0x12200004,0x10202004,0x12202004,
0x10000400,0x12000400,0x10002400,0x12002400,0x10200400,0x12200400,0x10202400,0x12202400,
0x10000404,0x12000404,0x10002404,0x12002404,0x10200404,0x12200404,0x10202404,0x12202404};

DWORD DESKEY3[]={
0x00000000,0x00000001,0x00040000,0x00040001,0x01000000,0x01000001,0x01040000,0x01040001,
0x00000002,0x00000003,0x00040002,0x00040003,0x01000002,0x01000003,0x01040002,0x01040003,
0x00000200,0x00000201,0x00040200,0x00040201,0x01000200,0x01000201,0x01040200,0x01040201,
0x00000202,0x00000203,0x00040202,0x00040203,0x01000202,0x01000203,0x01040202,0x01040203,
0x08000000,0x08000001,0x08040000,0x08040001,0x09000000,0x09000001,0x09040000,0x09040001,
0x08000002,0x08000003,0x08040002,0x08040003,0x09000002,0x09000003,0x09040002,0x09040003,
0x08000200,0x08000201,0x08040200,0x08040201,0x09000200,0x09000201,0x09040200,0x09040201,
0x08000202,0x08000203,0x08040202,0x08040203,0x09000202,0x09000203,0x09040202,0x09040203};

DWORD DESKEY4[]={
0x00000000,0x00100000,0x00000100,0x00100100,0x00000008,0x00100008,0x00000108,0x00100108,
0x00001000,0x00101000,0x00001100,0x00101100,0x00001008,0x00101008,0x00001108,0x00101108,
0x04000000,0x04100000,0x04000100,0x04100100,0x04000008,0x04100008,0x04000108,0x04100108,
0x04001000,0x04101000,0x04001100,0x04101100,0x04001008,0x04101008,0x04001108,0x04101108,
0x00020000,0x00120000,0x00020100,0x00120100,0x00020008,0x00120008,0x00020108,0x00120108,
0x00021000,0x00121000,0x00021100,0x00121100,0x00021008,0x00121008,0x00021108,0x00121108,
0x04020000,0x04120000,0x04020100,0x04120100,0x04020008,0x04120008,0x04020108,0x04120108,
0x04021000,0x04121000,0x04021100,0x04121100,0x04021008,0x04121008,0x04021108,0x04121108};

DWORD DESKEY5[]={
0x00000000,0x10000000,0x00010000,0x10010000,0x00000004,0x10000004,0x00010004,0x10010004,
0x20000000,0x30000000,0x20010000,0x30010000,0x20000004,0x30000004,0x20010004,0x30010004,
0x00100000,0x10100000,0x00110000,0x10110000,0x00100004,0x10100004,0x00110004,0x10110004,
0x20100000,0x30100000,0x20110000,0x30110000,0x20100004,0x30100004,0x20110004,0x30110004,
0x00001000,0x10001000,0x00011000,0x10011000,0x00001004,0x10001004,0x00011004,0x10011004,
0x20001000,0x30001000,0x20011000,0x30011000,0x20001004,0x30001004,0x20011004,0x30011004,
0x00101000,0x10101000,0x00111000,0x10111000,0x00101004,0x10101004,0x00111004,0x10111004,
0x20101000,0x30101000,0x20111000,0x30111000,0x20101004,0x30101004,0x20111004,0x30111004};

DWORD DESKEY6[]={
0x00000000,0x08000000,0x00000008,0x08000008,0x00000400,0x08000400,0x00000408,0x08000408,
0x00020000,0x08020000,0x00020008,0x08020008,0x00020400,0x08020400,0x00020408,0x08020408,
0x00000001,0x08000001,0x00000009,0x08000009,0x00000401,0x08000401,0x00000409,0x08000409,
0x00020001,0x08020001,0x00020009,0x08020009,0x00020401,0x08020401,0x00020409,0x08020409,
0x02000000,0x0A000000,0x02000008,0x0A000008,0x02000400,0x0A000400,0x02000408,0x0A000408,
0x02020000,0x0A020000,0x02020008,0x0A020008,0x02020400,0x0A020400,0x02020408,0x0A020408,
0x02000001,0x0A000001,0x02000009,0x0A000009,0x02000401,0x0A000401,0x02000409,0x0A000409,
0x02020001,0x0A020001,0x02020009,0x0A020009,0x02020401,0x0A020401,0x02020409,0x0A020409};

DWORD DESKEY7[]={
0x00000000,0x00000100,0x00080000,0x00080100,0x01000000,0x01000100,0x01080000,0x01080100,
0x00000010,0x00000110,0x00080010,0x00080110,0x01000010,0x01000110,0x01080010,0x01080110,
0x00200000,0x00200100,0x00280000,0x00280100,0x01200000,0x01200100,0x01280000,0x01280100,
0x00200010,0x00200110,0x00280010,0x00280110,0x01200010,0x01200110,0x01280010,0x01280110,
0x00000200,0x00000300,0x00080200,0x00080300,0x01000200,0x01000300,0x01080200,0x01080300,
0x00000210,0x00000310,0x00080210,0x00080310,0x01000210,0x01000310,0x01080210,0x01080310,
0x00200200,0x00200300,0x00280200,0x00280300,0x01200200,0x01200300,0x01280200,0x01280300,
0x00200210,0x00200310,0x00280210,0x00280310,0x01200210,0x01200310,0x01280210,0x01280310};

DWORD DESKEY8[]={
0x00000000,0x04000000,0x00040000,0x04040000,0x00000002,0x04000002,0x00040002,0x04040002,
0x00002000,0x04002000,0x00042000,0x04042000,0x00002002,0x04002002,0x00042002,0x04042002,
0x00000020,0x04000020,0x00040020,0x04040020,0x00000022,0x04000022,0x00040022,0x04040022,
0x00002020,0x04002020,0x00042020,0x04042020,0x00002022,0x04002022,0x00042022,0x04042022,
0x00000800,0x04000800,0x00040800,0x04040800,0x00000802,0x04000802,0x00040802,0x04040802,
0x00002800,0x04002800,0x00042800,0x04042800,0x00002802,0x04002802,0x00042802,0x04042802,
0x00000820,0x04000820,0x00040820,0x04040820,0x00000822,0x04000822,0x00040822,0x04040822,
0x00002820,0x04002820,0x00042820,0x04042820,0x00002822,0x04002822,0x00042822,0x04042822};

DWORD DESSpBox1[]={
0x02080800,0x00080000,0x02000002,0x02080802,0x02000000,0x00080802,0x00080002,0x02000002,
0x00080802,0x02080800,0x02080000,0x00000802,0x02000802,0x02000000,0x00000000,0x00080002,
0x00080000,0x00000002,0x02000800,0x00080800,0x02080802,0x02080000,0x00000802,0x02000800,
0x00000002,0x00000800,0x00080800,0x02080002,0x00000800,0x02000802,0x02080002,0x00000000,
0x00000000,0x02080802,0x02000800,0x00080002,0x02080800,0x00080000,0x00000802,0x02000800,
0x02080002,0x00000800,0x00080800,0x02000002,0x00080802,0x00000002,0x02000002,0x02080000,
0x02080802,0x00080800,0x02080000,0x02000802,0x02000000,0x00000802,0x00080002,0x00000000,
0x00080000,0x02000000,0x02000802,0x02080800,0x00000002,0x02080002,0x00000800,0x00080802};

DWORD DESSpBox2[]={
0x40108010,0x00000000,0x00108000,0x40100000,0x40000010,0x00008010,0x40008000,0x00108000,
0x00008000,0x40100010,0x00000010,0x40008000,0x00100010,0x40108000,0x40100000,0x00000010,
0x00100000,0x40008010,0x40100010,0x00008000,0x00108010,0x40000000,0x00000000,0x00100010,
0x40008010,0x00108010,0x40108000,0x40000010,0x40000000,0x00100000,0x00008010,0x40108010,
0x00100010,0x40108000,0x40008000,0x00108010,0x40108010,0x00100010,0x40000010,0x00000000,
0x40000000,0x00008010,0x00100000,0x40100010,0x00008000,0x40000000,0x00108010,0x40008010,
0x40108000,0x00008000,0x00000000,0x40000010,0x00000010,0x40108010,0x00108000,0x40100000,
0x40100010,0x00100000,0x00008010,0x40008000,0x40008010,0x00000010,0x40100000,0x00108000};

DWORD DESSpBox3[]={
0x04000001,0x04040100,0x00000100,0x04000101,0x00040001,0x04000000,0x04000101,0x00040100,
0x04000100,0x00040000,0x04040000,0x00000001,0x04040101,0x00000101,0x00000001,0x04040001,
0x00000000,0x00040001,0x04040100,0x00000100,0x00000101,0x04040101,0x00040000,0x04000001,
0x04040001,0x04000100,0x00040101,0x04040000,0x00040100,0x00000000,0x04000000,0x00040101,
0x04040100,0x00000100,0x00000001,0x00040000,0x00000101,0x00040001,0x04040000,0x04000101,
0x00000000,0x04040100,0x00040100,0x04040001,0x00040001,0x04000000,0x04040101,0x00000001,
0x00040101,0x04000001,0x04000000,0x04040101,0x00040000,0x04000100,0x04000101,0x00040100,
0x04000100,0x00000000,0x04040001,0x00000101,0x04000001,0x00040101,0x00000100,0x04040000};

DWORD DESSpBox4[]={
0x00401008,0x10001000,0x00000008,0x10401008,0x00000000,0x10400000,0x10001008,0x00400008,
0x10401000,0x10000008,0x10000000,0x00001008,0x10000008,0x00401008,0x00400000,0x10000000,
0x10400008,0x00401000,0x00001000,0x00000008,0x00401000,0x10001008,0x10400000,0x00001000,
0x00001008,0x00000000,0x00400008,0x10401000,0x10001000,0x10400008,0x10401008,0x00400000,
0x10400008,0x00001008,0x00400000,0x10000008,0x00401000,0x10001000,0x00000008,0x10400000,
0x10001008,0x00000000,0x00001000,0x00400008,0x00000000,0x10400008,0x10401000,0x00001000,
0x10000000,0x10401008,0x00401008,0x00400000,0x10401008,0x00000008,0x10001000,0x00401008,
0x00400008,0x00401000,0x10400000,0x10001008,0x00001008,0x10000000,0x10000008,0x10401000};

DWORD DESSpBox5[]={
0x08000000,0x00010000,0x00000400,0x08010420,0x08010020,0x08000400,0x00010420,0x08010000,
0x00010000,0x00000020,0x08000020,0x00010400,0x08000420,0x08010020,0x08010400,0x00000000,
0x00010400,0x08000000,0x00010020,0x00000420,0x08000400,0x00010420,0x00000000,0x08000020,
0x00000020,0x08000420,0x08010420,0x00010020,0x08010000,0x00000400,0x00000420,0x08010400,
0x08010400,0x08000420,0x00010020,0x08010000,0x00010000,0x00000020,0x08000020,0x08000400,
0x08000000,0x00010400,0x08010420,0x00000000,0x00010420,0x08000000,0x00000400,0x00010020,
0x08000420,0x00000400,0x00000000,0x08010420,0x08010020,0x08010400,0x00000420,0x00010000,
0x00010400,0x08010020,0x08000400,0x00000420,0x00000020,0x00010420,0x08010000,0x08000020};

DWORD DESSpBox6[]={
0x80000040,0x00200040,0x00000000,0x80202000,0x00200040,0x00002000,0x80002040,0x00200000,
0x00002040,0x80202040,0x00202000,0x80000000,0x80002000,0x80000040,0x80200000,0x00202040,
0x00200000,0x80002040,0x80200040,0x00000000,0x00002000,0x00000040,0x80202000,0x80200040,
0x80202040,0x80200000,0x80000000,0x00002040,0x00000040,0x00202000,0x00202040,0x80002000,
0x00002040,0x80000000,0x80002000,0x00202040,0x80202000,0x00200040,0x00000000,0x80002000,
0x80000000,0x00002000,0x80200040,0x00200000,0x00200040,0x80202040,0x00202000,0x00000040,
0x80202040,0x00202000,0x00200000,0x80002040,0x80000040,0x80200000,0x00202040,0x00000000,
0x00002000,0x80000040,0x80002040,0x80202000,0x80200000,0x00002040,0x00000040,0x80200040};

DWORD DESSpBox7[]={
0x00004000,0x00000200,0x01000200,0x01000004,0x01004204,0x00004004,0x00004200,0x00000000,
0x01000000,0x01000204,0x00000204,0x01004000,0x00000004,0x01004200,0x01004000,0x00000204,
0x01000204,0x00004000,0x00004004,0x01004204,0x00000000,0x01000200,0x01000004,0x00004200,
0x01004004,0x00004204,0x01004200,0x00000004,0x00004204,0x01004004,0x00000200,0x01000000,
0x00004204,0x01004000,0x01004004,0x00000204,0x00004000,0x00000200,0x01000000,0x01004004,
0x01000204,0x00004204,0x00004200,0x00000000,0x00000200,0x01000004,0x00000004,0x01000200,
0x00000000,0x01000204,0x01000200,0x00004200,0x00000204,0x00004000,0x01004204,0x01000000,
0x01004200,0x00000004,0x00004004,0x01004204,0x01000004,0x01004200,0x01004000,0x00004004};

DWORD DESSpBox8[]={
0x20800080,0x20820000,0x00020080,0x00000000,0x20020000,0x00800080,0x20800000,0x20820080,
0x00000080,0x20000000,0x00820000,0x00020080,0x00820080,0x20020080,0x20000080,0x20800000,
0x00020000,0x00820080,0x00800080,0x20020000,0x20820080,0x20000080,0x00000000,0x00820000,
0x20000000,0x00800000,0x20020080,0x20800080,0x00800000,0x00020000,0x20820000,0x00000080,
0x00800000,0x00020000,0x20000080,0x20820080,0x00020080,0x20000000,0x00000000,0x00820000,
0x20800080,0x20020080,0x20020000,0x00800080,0x20820000,0x00000080,0x00800080,0x20020000,
0x20820080,0x00800000,0x20800000,0x20000080,0x00820000,0x00020080,0x20020080,0x20800000,
0x00000080,0x20820000,0x00820080,0x00000000,0x20000000,0x20800080,0x00020000,0x00820080};

void main(int argc,char ** argv)
{
    WSADATA WSAData;
    SOCKET sock;
    SOCKADDR_IN addr_in;
    int len;
    char serverip[]="192.168.13.211";
    short port=445;
    WORD olen,nlen;
    unsigned char buf1[0x1000];
    SMBP smbp;
    HMODULE hNtdll = NULL;

    hNtdll = LoadLibrary( "ntdll.dll" );
    if ( !hNtdll )
    {
        printf( "LoadLibrary( NTDLL.DLL ) Error:%d\n", GetLastError() );
        return ;
    }
    RtlUpcaseUnicodeStringToOemString = (RTLUPCASEUNICODESTRINGTOOEMSTRING)
        GetProcAddress(    hNtdll,    "RtlUpcaseUnicodeStringToOemString");
    if (WSAStartup(MAKEWORD(2,0),&WSAData)!=0)
    {
        printf("WSAStartup error.Error:%d\n",WSAGetLastError());
        return;
    }

    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(port);
    addr_in.sin_addr.S_un.S_addr=inet_addr(serverip);
    
    if ((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
    {
        printf("Socket failed.Error:%d\n",WSAGetLastError());
        return;
    }
    if(WSAConnect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in),NULL,NULL,NULL,NULL)==SOCKET_ERROR)
    {
        printf("Connect failed.Error:%d",WSAGetLastError());
        return;
    }
    SmbNegotiate(&smbp);
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    SmbSessionSetupAndX1(&smbp);
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    if((buf1[0]==0xff)&&(buf1[1]=='S')&&(buf1[2]=='M')&&(buf1[3]=='B'))
        olen=0x20;
    else if((buf1[4]==0xff)&&(buf1[5]=='S')&&(buf1[6]=='M')&&(buf1[7]=='B'))
        olen=0x24;
    else
        return;
    smbp.smbinfo.userid =  *(WORD *)(buf1+olen-0x4);
    nlen=*(WORD *)(buf1+olen+1+2*3);//BLOB的长度
    olen=olen+1+2*buf1[olen]+2;
    memcpy(challage,buf1+olen+0x18,8);
    SmbSessionSetupAndX2(&smbp,L"administrator",L"FXNB",L"asdasd");
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    if((buf1[0]==0xff)&&(buf1[1]=='S')&&(buf1[2]=='M')&&(buf1[3]=='B'))
        olen=0x20;
    else if((buf1[4]==0xff)&&(buf1[5]=='S')&&(buf1[6]=='M')&&(buf1[7]=='B'))
        olen=0x24;
    else
        return;
    if(buf1[olen]==0)
        printf("error username and password\n");
    else
        printf("login ok\n");
    WSACleanup();
    return;
}

void SmbSessionSetupAndX1(SMBP * psmbp)
{
    unsigned char sb[0x20]={
0x4E,0x54,0x4C,0x4D,0x53,0x53,0x50,0x00,0x01,0x00,0x00,0x00,0x97,0x82,0x08,0xE0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

    psmbp->smbinfo.smbtoken =0x73; 
    memset(psmbp->smbinfo.info,0,0x200); 
    psmbp->smbinfo.flagsummary2 = 0xc807;
    *(DWORD *)(psmbp->smbinfo.info+21) = 0x800000D4;
    //指定使用加密的FLAG
    psmbp->smbinfo.info[0]=0xc;//WORD 参数个数
    *(WORD *)(psmbp->smbinfo.info+1)=0Xff;//无下一个命令
    *(WORD *)(psmbp->smbinfo.info+3)=0Xb0;//下一命令偏移
    *(WORD *)(psmbp->smbinfo.info+5)=0X4104;//最大缓冲
    *(WORD *)(psmbp->smbinfo.info+7)=0X32;//最大的MPX
    *(WORD *)(psmbp->smbinfo.info+9)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+11)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+17)=0X0;//保留

    *(WORD *)(psmbp->smbinfo.info+15)=0x20;  //BLOB的长度
    memcpy(psmbp->smbinfo.info+27,sb,0x20);//放入BLOB
    memcpy(psmbp->smbinfo.info+28+0x20,navos,36);//
    memcpy(psmbp->smbinfo.info+66+0x20,lanman,32);//
    *(WORD *)(psmbp->smbinfo.info+25)=73+0x20;
    psmbp->smbnbt.smbpacketlen = htons(132+0x20);
}

void SmbSessionSetupAndX2(SMBP * psmbp,wchar_t * username,wchar_t * domainname,wchar_t * password)
{
    unsigned char enkey[8];
    unsigned char cread[0x40];
    unsigned char passwordhash[0x20];
    unsigned char creaded[0x100];
    int ulen;
    int dlen;
    int i;
    for(i=0;i<0x20;i++)
    {
        if(username[i]==0)
            break;
    }
    ulen=2*i;
    for(i=0;i<0x20;i++)
    {
        if(domainname[i]==0)
            break;
    }
    dlen=2*i;

    memset(creaded,0,0x100);
    memcpy(creaded,"NTLMSSP",8);
    *(DWORD *)(creaded+8)=3;
    *(WORD *)(creaded+0xc)=0x18;
    *(WORD *)(creaded+0xe)=0x18;
    *(DWORD *)(creaded+0x10)=0x40+ulen+dlen+dlen;
    *(WORD *)(creaded+0x14)=0x18;
    *(WORD *)(creaded+0x16)=0x18;
    *(DWORD *)(creaded+0x18)=0x40+ulen+dlen+dlen+0x18;
    *(WORD *)(creaded+0x1c)=dlen;
    *(WORD *)(creaded+0x1e)=dlen;
    *(DWORD *)(creaded+0x20)=0x40;
    *(WORD *)(creaded+0x24)=ulen;
    *(WORD *)(creaded+0x26)=ulen;
    *(DWORD *)(creaded+0x28)=0x40+dlen;
    *(WORD *)(creaded+0x2c)=dlen;
    *(WORD *)(creaded+0x2e)=dlen;
    *(DWORD *)(creaded+0x30)=0x40+dlen+ulen;
    *(WORD *)(creaded+0x34)=0x10;
    *(WORD *)(creaded+0x36)=0x10;
    *(DWORD *)(creaded+0x38)=0x40+ulen+dlen+dlen+0x30;
    *(DWORD *)(creaded+0x3C)=0XE0888215;
    //放如用户名等信息
    memcpy(creaded+0x40,domainname,dlen);
    memcpy(creaded+0x40+dlen,username,ulen);
    memcpy(creaded+0x40+dlen+ulen,domainname,dlen);
    psmbp->smbinfo.smbtoken =0x73; 
    memset(psmbp->smbinfo.info,0,0x200); 
    psmbp->smbinfo.flagsummary2 = 0xc807;
    *(DWORD *)(psmbp->smbinfo.info+21) = 0x800000D4;
    //指定使用加密的FLAG
    psmbp->smbinfo.info[0]=0xc;//WORD 参数个数
    *(WORD *)(psmbp->smbinfo.info+1)=0Xff;//无下一个命令
    *(WORD *)(psmbp->smbinfo.info+3)=0X12e;//下一命令偏移
    *(WORD *)(psmbp->smbinfo.info+5)=0X4104;//最大缓冲
    *(WORD *)(psmbp->smbinfo.info+7)=0X32;//最大的MPX
    *(WORD *)(psmbp->smbinfo.info+9)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+11)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+17)=0X0;//保留

    passtoowf(password,passwordhash);    //口令到散列
    challagetorkey(romkey,challage,enkey);    //把挑战和任意一个本地随机KEY通过MD5计算出加密KEY
    memset(cread,0,0x40);
    memcpy(cread,romkey,0x8);    //BLOB中放入本地随机KEY,好让服务器知道能计算出加密KEY
    hashtocread(enkey,passwordhash,cread);    //通过加密KEY计算NTLM的加密形式
    memcpy(creaded+0x40+ulen+dlen+dlen,cread,0x40);    
    *(WORD *)(psmbp->smbinfo.info+15)=0x80+ulen+dlen+dlen;  //BLOB的长度
    memcpy(psmbp->smbinfo.info+27,creaded,0x80+ulen+dlen+dlen);//放入BLOB
    memcpy(psmbp->smbinfo.info+28+0x80+ulen+dlen+dlen,navos,36);//
    memcpy(psmbp->smbinfo.info+66+0x80+ulen+dlen+dlen,lanman,32);//
    *(WORD *)(psmbp->smbinfo.info+25)=73+0x80+ulen+dlen+dlen;
    psmbp->smbnbt.smbpacketlen = htons(132+ 0x80+ulen+dlen+dlen);
}

void SmbNegotiate(SMBP * psmbp)
{
    unsigned char magic[4]={0xff,'S','M','B'};
    short len;
    char langitem1[]="PC NETWORK PROGRAM 1.0";
    char langitem2[]="LANMAN1.0";
    char langitem3[]="Windows for Workgroups 3.1a";
    char langitem4[]="LM1.2X002";
    char langitem5[]="LANMAN2.1";
    char langitem6[]="NT LM 0.12";
    char langitem7[]="PCLAN1.0";
    char langitem8[]="MICROSOFT NETWORKS 1.03";
    char langitem9[]="MICROSOFT NETWORKS 3.0";
    char langitem10[]="DOS LM1.2X002";
    char langitem11[]="DOS LANMAN2.1";
    char langitem12[]="Cairo 0.xa";

    memset(psmbp,0,sizeof(SMBP));
    psmbp->smbnbt.nbtsmb = 0;
    psmbp->smbnbt.flag = 0;
    memcpy(psmbp->smbinfo.magic, magic,4);
    psmbp->smbinfo.smbtoken = 0x72; 
    psmbp->smbinfo.errcodeclass = 0x0;
    psmbp->smbinfo.dosaherrcode = 0x0;
    psmbp->smbinfo.errcode[0] = 0x0;
    psmbp->smbinfo.errcode[1] = 0x0;
    psmbp->smbinfo.flagsummary = 0x18;
    psmbp->smbinfo.flagsummary2 = 0xc853;
    //指定了带挑战方式支持的FLAG
    psmbp->smbinfo.callprocessid = 0xfeff;
    psmbp->smbinfo.multiplexid = 0;
    psmbp->smbinfo.info[0]=0x0;
    len=3+2*(psmbp->smbinfo.info[0]);
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem6,sizeof(langitem6));
    len = len+1+sizeof(langitem6);

    *(WORD *)(psmbp->smbinfo.info+1) =len-3-2*(psmbp->smbinfo.info[0]);
    psmbp->smbnbt.smbpacketlen = htons(len+0x20); 
}

void challagetorkey(unsigned char * romkey,unsigned char * challage,unsigned char * enkey)
{
    unsigned char LM[0x58];
    md5init(LM);
    *(DWORD *)LM=0x200;
    memcpy(LM+0X18,challage,8);
    memcpy(LM+0X20,romkey,8);
    *(DWORD *)(LM+0x28)=0x80;
    *(DWORD *)(LM+0x50)=0x80;
    md5final(LM);
    memcpy(enkey,LM+8,8);
}

void hashtocread(unsigned char * enkey,unsigned char * hash,unsigned char * cread)
{
    unsigned char LmPass[0x10];
    unsigned char rc4keylist[0x102];
    LSA_UNICODE_STRING lmhash;
    unsigned char desecb[128];
    unsigned char lm[0x28];
    unsigned char key[0x8];
    unsigned char rc4key[0x10];
//
加密KEY加密NTLM
    initLMP(hash,LmPass);
    deskey(LmPass,desecb);
    des(lm,enkey,desecb,1);
    initLMP(hash+7,LmPass);
    deskey(LmPass,desecb);
    des(lm+8,enkey,desecb,1);
    memset(key,0,8);
    memcpy(key,hash+0xe,2);
    initLMP(key,LmPass);
    deskey(LmPass,desecb);
    des(lm+0x10,enkey,desecb,1);
    memcpy(cread+0x18,lm,0x18);
//计算NTLMRC4形式
    lmhash.Length=0x10;
    lmhash.MaximumLength=0x10;
    lmhash.Buffer= hash;
    initMDP(&lmhash,rc4key);
    hmacmd5(rc4key,enkey);
    memcpy(cread+0x30,rc4key,0x10);
    rc4_key(rc4keylist,rc4key,0x10);    
//由于并未使用此字段认证,下面的函数未实现,就以RC4KEY做其放进去了
//    rc4_424(rc4keylist,rc4rom,0x10);
}

void rc4_key(unsigned char * rc4keylist,unsigned char * rc4key,int keylen)
{
    int i,j;
    DWORD a1=0x03020100;
    unsigned char c1,c2,c3;
    for(i=0;i<0x40;i++)
    {
        *(DWORD *)(rc4keylist+4*i)=a1;
        a1+=0x04040404;
    }
    rc4keylist[0x100]=0;
    rc4keylist[0x101]=0;
    j=0;
    i=0;
    c3=0;
    for(j=0;j<0x100;j++)
    {
        c1=rc4keylist[j];
        c2=rc4key[i];
        c3=(c3+c2+c1)%256;
        rc4keylist[j]=rc4keylist[c3];
        rc4keylist[c3]=c1;
        i++;
        if(i==keylen)
            i=0;
    }
}

void hmacmd5(unsigned char * rc4key,unsigned char * enkey)
{
    unsigned char Lm1[0x58];
    unsigned char Lm2[0x58];
    unsigned char k1[0x40];
    unsigned char k2[0x40];
    int i;
    md5init(Lm1);
    md5init(Lm2);
    memset(k1,0,0x40);
    memset(k2,0,0x40);
    memcpy(k1,rc4key,0x10);
    memcpy(k2,rc4key,0x10);
    for(i=0;i<0x10;i++)
    {
        *(DWORD *)(k1+4*i)=(*(DWORD *)(k1+4*i))^0x36363636;
        *(DWORD *)(k2+4*i)=(*(DWORD *)(k2+4*i))^0x5c5c5c5c;
    }
    *(DWORD *)Lm1=0x200;
    memcpy(Lm1+0X18,k1,0x40);
    md5final(Lm1);
    *(DWORD *)Lm2=0x200;
    memcpy(Lm2+0X18,k2,0x40);
    md5final(Lm2);
    *(DWORD *)Lm1=0x400;
    memcpy(Lm1+0X18,challage,0x8);
    memcpy(Lm1+0X20,romkey,0x8);
    memset(Lm1+0X28,0x80,1);
    memset(Lm1+0X29,0,0x2f);
    *(DWORD *)(Lm1+0x50)=0x280;
    md5final(Lm1);
    memcpy(Lm2+0X18,Lm1+8,0x10);
    *(DWORD *)Lm2=0x400;
    memset(Lm2+0X28,0x80,1);
    memset(Lm2+0X29,0,0x2f);
    *(DWORD *)(Lm2+0x50)=0x280;
    md5final(Lm2);
    memcpy(rc4key,Lm2+8,0x10);
}

void passtoowf(wchar_t * password,unsigned char * paswdowf)
{
    int len;
    int i;
    LSA_UNICODE_STRING pass;
    LSA_UNICODE_STRING opass;
    char magic1[8]="KGS!@#$%";
    unsigned char desecb[128];
    unsigned char upassword[0x10];
    unsigned char LmPass[0x10];

    len=0;
    for(i=0;i<0x20;i++)
    {
        if(password[i]==0 )
            break;
        len=len+2;
    }
    if(len>28)
    {
        printf("password <=14");
        return;
    }
    pass.Length=len;
    pass.MaximumLength=len;
    pass.Buffer=password;
    opass.MaximumLength=0xf;
    opass.Buffer=upassword;
    memset(upassword,0,0x10);
    RtlUpcaseUnicodeStringToOemString(&opass,&pass,0);
    initLMP(upassword,LmPass);
    deskey(LmPass,desecb);
    des(paswdowf+0x10,magic1,desecb,1);
    initLMP(upassword+7,LmPass);
    deskey(LmPass,desecb);
    des(paswdowf+0x18,magic1,desecb,1);
    initMDP(&pass,paswdowf);
}

void initMDP(PLSA_UNICODE_STRING pass,unsigned char * LM)
{
    unsigned char LM1[0x58];
    unsigned char s[2]="0";
    md4init(LM1);
    memcpy(LM1+0x18,pass->Buffer,pass->Length);
    memset(LM1+0x18+pass->Length,0x80,1);
    memset(LM1+0x18+pass->Length+1,0,0x37-pass->Length);
    *(DWORD *)(LM1+0x50)=8*(pass->Length);
    memset(LM1+0x51,0x0,7);
    *(DWORD *)(LM1+0x10)=0x200;
    md4(LM1);
    memcpy(LM,LM1,16);
}

void md4init(unsigned char * LM)
{
    *(DWORD *)(LM)=0x67452301;
    *(DWORD *)(LM+4)=0xefcdab89;
    *(DWORD *)(LM+8)=0x98badcfe;
    *(DWORD *)(LM+0xc)=0x10325476;
    *(DWORD *)(LM+0x10)=0;
    *(DWORD *)(LM+0x14)=0;
}

void md4(unsigned char * LM)
{
    DWORD d1,d2,d3,d4;
    DWORD a1,a2,a3;
    //1
    d1=*(DWORD *)(LM);
    d2=*(DWORD *)(LM+4);
    d3=*(DWORD *)(LM+8);
    d4=*(DWORD *)(LM+0xc);
    a1=*(DWORD *)(LM+0x18);
    a2=(((d4^d3)&d2)^d4)+a1+d1;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x1c);
    a3=(((d3^d2)&a2)^d3)+a1;
    d4=d4+a3;
    d4=(d4<<7)|(d4>>0x19);
    a1=*(DWORD *)(LM+0x20);
    a3=(((d2^a2)&d4)^d2)+a1;
    d3=d3+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x24);
    a3=(((d4^a2)&d3)^a2)+a1;
    d2=d2+a3;
    d2=(d2<<0x13)|(d2>>0xd);
    a1=*(DWORD *)(LM+0x28);
    a3=(((d4^d3)&d2)^d4)+a1;
    a2=a2+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x2c);
    a3=(((d3^d2)&a2)^d3)+a1;
    d4=d4+a3;
    d4=(d4<<7)|(d4>>0x19);
    a1=*(DWORD *)(LM+0x30);
    a3=(((d2^a2)&d4)^d2)+a1;
    d3=d3+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x34);
    a3=(((d4^a2)&d3)^a2)+a1;
    d2=d2+a3;
    d2=(d2<<0x13)|(d2>>0xd);
    a1=*(DWORD *)(LM+0x38);
    a3=(((d4^d3)&d2)^d4)+a1;
    a2=a2+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x3c);
    a3=(((d3^d2)&a2)^d3)+a1;
    d4=d4+a3;
    d4=(d4<<7)|(d4>>0x19);
    a1=*(DWORD *)(LM+0x40);
    a3=(((d2^a2)&d4)^d2)+a1;
    d3=d3+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x44);
    a3=(((d4^a2)&d3)^a2)+a1;
    d2=d2+a3;
    d2=(d2<<0x13)|(d2>>0xd);
    a1=*(DWORD *)(LM+0x48);
    a3=(((d4^d3)&d2)^d4)+a1;
    a2=a2+a3;
    a2=(a2<<0x3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x4c);
    a3=(((d3^d2)&a2)^d3)+a1;
    d4=d4+a3;
    d4=(d4<<7)|(d4>>0x19);
    a1=*(DWORD *)(LM+0x50);
    a3=(((d2^a2)&d4)^d2)+a1;
    d3=d3+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x54);
    a3=(((d4^a2)&d3)^a2)+a1;
    d2=d2+a3;
    d2=(d2<<0x13)|(d2>>0xd);
    //2
    a1=*(DWORD *)(LM+0x18);
    a3=(((d3|d2)&d4)|(d3&d2))+a1+0x5a827999;
    a2=a2+a3;    
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x28);
    a3=(((d2|a2)&d3)|(d2&a2))+0x5a827999;
    d4=d4+a1+a3;
    d4=(d4<<5)|(d4>>0x1b);
    a1=*(DWORD *)(LM+0x38);
    a3=(((d4|a2)&d2)|(d4&a2))+a1+0x5a827999;
    d3=d3+a3;
    d3=(d3<<9)|(d3>>0x17);
    a1=*(DWORD *)(LM+0x48);
    a3=(((d4|d3)&a2)|(d4&d3))+a1+0x5a827999;
    d2=d2+a3;
    d2=(d2<<0xd)|(d2>>0x13);
    a1=*(DWORD *)(LM+0x1c);
    a3=(((d3|d2)&d4)|(d3&d2))+a1+0x5a827999;
    a2=a2+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x2c);
    a3=(((d2|a2)&d3)|(d2&a2))+0x5a827999;
    d4=d4+a1+a3;
    d4=(d4<<5)|(d4>>0x1b);
    a1=*(DWORD *)(LM+0x3c);
    a3=(((d4|a2)&d2)|(d4&a2))+a1+0x5a827999;
    d3=d3+a3;
    d3=(d3<<9)|(d3>>0x17);
    a1=*(DWORD *)(LM+0x4c);
    a3=(((d4|d3)&a2)|(d4&d3))+a1+0x5a827999;
    d2=d2+a3;
    d2=(d2<<0xd)|(d2>>0x13);
    a1=*(DWORD *)(LM+0x20);
    a3=(((d3|d2)&d4)|(d3&d2))+a1+0x5a827999;
    a2=a2+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x30);
    a3=(((d2|a2)&d3)|(d2&a2))+0x5a827999;
    d4=d4+a1+a3;
    d4=(d4<<5)|(d4>>0x1b);
    a1=*(DWORD *)(LM+0x40);
    a3=(((d4|a2)&d2)|(d4&a2))+0x5a827999;
    d3=d3+a1+a3;
    d3=(d3<<9)|(d3>>0x17);
    a1=*(DWORD *)(LM+0x50);
    a3=(((d4|d3)&a2)|(d4&d3))+a1+0x5a827999;
    d2=d2+a3;
    d2=(d2<<0xd)|(d2>>0x13);
    a1=*(DWORD *)(LM+0x24);
    a3=(((d3|d2)&d4)|(d3&d2))+a1+0x5a827999;
    a2=a2+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x34);
    a3=(((d2|a2)&d3)|(d2&a2))+0x5a827999;
    d4=d4+a1+a3;
    d4=(d4<<5)|(d4>>0x1b);
    a1=*(DWORD *)(LM+0x44);
    a3=(((d4|a2)&d2)|(d4&a2))+a1+0x5a827999;
    d3=d3+a3;
    d3=(d3<<9)|(d3>>0x17);    
    a1=*(DWORD *)(LM+0x54);
    a3=(((d4|d3)&a2)|(d4&d3))+a1+0x5a827999;
    d2=d2+a3;
    d2=(d2<<0xd)|(d2>>0x13);    
    //3
    a1=*(DWORD *)(LM+0x18);
    a3=((d4^d3)^d2)+a1;
    a2=a2+0x6ed9eba1+a3;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x38);
    a3=((d3^d2)^a2)+a1;
    d4=d4+0x6ed9eba1+a3;
    d4=(d4<<9)|(d4>>0x17);
    a1=*(DWORD *)(LM+0x28);
    a3=((d4^d2)^a2)+a1;
    d3=d3+0x6ed9eba1+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x48);
    a3=d4^d3;
    d2=d2+a1+0x6ed9eba1+(a2^a3);
    d2=(d2<<0xf)|(d2>>0x11);
    a1=*(DWORD *)(LM+0x20);
    a2=a2+((d2^a3)+a1+0x6ed9eba1);
    a3=d3^d2;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x40);
    a3=(a3^a2)+a1;
    d4=d4+0x6ed9eba1+a3;
    d4=(d4<<9)|(d4>>0x17);
    a1=*(DWORD *)(LM+0x30);
    a3=((d4^d2)^a2)+a1;
    d3=d3+0x6ed9eba1+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x50);
    a3=d4^d3;
    d2=d2+a1+0x6ed9eba1+(a2^a3);
    d2=(d2<<0xf)|(d2>>0x11);
    a1=*(DWORD *)(LM+0x1c);
    a2=a2+0x6ed9eba1+((d2^a3)+a1);
    a3=d3^d2;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x3c);
    a3=(a3^a2)+a1;
    d4=d4+0x6ed9eba1+a3;
    d4=(d4<<9)|(d4>>0x17);
    a1=*(DWORD *)(LM+0x2c);
    a3=((d4^d2)^a2)+a1;
    d3=d3+0x6ed9eba1+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x4c);
    a3=d4^d3;
    d2=d2+a1+0x6ed9eba1+(a2^a3);
    d2=(d2<<0xf)|(d2>>0x11);
    a1=*(DWORD *)(LM+0x24);
    a2=a2+0x6ed9eba1+((d2^a3)+a1);
    a3=d3^d2;
    a2=(a2<<3)|(a2>>0x1d);
    a1=*(DWORD *)(LM+0x44);
    a3=(a3^a2)+a1;
    d4=d4+0x6ed9eba1+a3;
    d4=(d4<<9)|(d4>>0x17);
    a1=*(DWORD *)(LM+0x34);
    a3=((d4^d2)^a2)+a1;
    d3=d3+0x6ed9eba1+a3;
    d3=(d3<<0xb)|(d3>>0x15);
    a1=*(DWORD *)(LM+0x54);
    a3=((d4^a2)^d3)+a1;
    d2=d2+0x6ed9eba1+a3;
    d2=(d2<<0xf)|(d2>>0x11);
    *(DWORD *)(LM)=a2+*(DWORD *)(LM);
    *(DWORD *)(LM+4)=d2+*(DWORD *)(LM+4);
    *(DWORD *)(LM+8)=d3+*(DWORD *)(LM+8);
    *(DWORD *)(LM+0xc)=d4+*(DWORD *)(LM+0xc);
}

void initLMP(char * pass,unsigned char * LM)
{
    char LmPass[0x20];
    DWORD d1,d2;
    unsigned char a1,a2;
    char a3[]={1,3,7,0xf,0x1f,0x3f,0x7f};
    int i;

    for(i=0;i<8;i++)
    {
        if(i==0)
        {
            a1=pass[0];
            LmPass[0]=a1>>1;
        }
        else if(i==7)
        {
            a1=pass[i-1];
            a1=a1&a3[i-1];            
            LmPass[i]=a1;
        }
        else
        {
            a1=pass[i-1];
            a2=pass[i];
            a1=a1&a3[i-1];
            a1=a1<<(7-i);
            a2=a2>>(i+1);
            LmPass[i]=a1|a2;
        }
    }
    d1=*(DWORD *)LmPass;
    d2=*(DWORD *)(LmPass+4);
    d1=(d1&0xff7f7f7f)<<1;
    d2=(d2&0xff7f7f7f)<<1;
    *(DWORD *)LmPass=d1;
    *(DWORD *)(LmPass+4)=d2;
    //
    for(i=0;i<8;i++)
    {
        a1=LmPass[i];
        a2=a1;
        a1=a1&0xf;
        a2=a2>>4;
        a2=DESParity[a2];
        a1=DESParity[a1];
        a2=a1+a2;
        a2=a2^a1;
        a2=a2-a1;
        a2=a2&1;
        a2=a2^a1;
        a2=a2-a1;
        if(a2==0)
            LmPass[i]=LmPass[i]^1;
    }
    memcpy(LM,LmPass,8);
    //deskey(LmPass,desecb);
    //des(LM,magic1,desecb,1);
}

void deskey(char * LmPass,unsigned char * desecb)
{
    int i;
    unsigned char a1;
    DWORD d1,d2,d3,d4,d5,d6;


    d1=*(DWORD *)LmPass;
    d2=*(DWORD *)(LmPass+4);
    d2=d2>>4;
    d1=d1&0xf0f0f0f;
    d2=d2&0xf0f0f0f;
    d2=d2^d1;
    d1=(*(DWORD *)LmPass)^d2;
    d2=d2<<4;
    d2=(*(DWORD *)(LmPass+4))^d2;
    d3=d1&0xfffff333;
    d3=d3<<0x12;
    d4=d1&0xcccc0000;
    d4=d4^d3;
    d3=d4;
    d3=d3>>0x12;
    d3=d3^d4;
    d1=d1^d3;
    d3=d2&0xfffff333;
    d3=d3<<0x12;
    d4=d2&0xcccc0000;
    d4=d4^d3;
    d3=d4>>0x12;
    d3=d3^d4;
    d2=d2^d3;
    d3=d1;
    d4=d2>>1;
    d3=d3&0x55555555;
    d4=d4&0x55555555;
    d4=d4^d3;
    d1=d1^d4;
    d4=d4+d4;
    d2=d2^d4;
    d4=d1>>8;
    d3=d2&0xff00ff;
    d4=d4&0xff00ff;
    d4=d4^d3;
    d2=d2^d4;
    d4=d4<<8;
    d1=d1^d4;
    d4=d2>>1;
    d3=d1;
    d3=d3&0x55555555;
    d4=d4&0x55555555;
    d4=d4^d3;
    d1=d1^d4;
    d4=d4+d4;
    d2=d2^d4;
    d3=d1&0xf000000f;
    d4=(d2>>0xc)&0xff0;
    d1=d1&0x0fffffff;
    d3=(d3|d4)>>4;
    d4=d2&0xff00;
    d2=(d2&0xff)<<0x10;
    d3=d3|d4;
    d3=d3|d2;
    for(i=0;i<16;i++)
    {
        d2=d1;
        a1=DESDShift[i];
        if(a1==0)
        {
            d2=d2>>1;
            d1=d1<<0x1b;
            d4=d3>>1;
            d3=d3<<0x1b;
            d1=d1|d2;            
        }
        else
        {
            d2=d2>>2;
            d1=d1<<0x1a;
            d4=d3>>2;
            d3=d3<<0x1a;
            d1=d1|d2;
        }
        d1=d1&0x0fffffff;
        d3=d3|d4;
        d2=d1>>1;
        d4=d1&0xc00000;
        d4=d4|(d2&0x07000000);
        d4=(d4>>1)|(d1&0x00100000);
        //d6=d2&0x00060000;
        d5=(d1&0x0001e000)|(d2&0x00060000);
        d2=d2&0x00000f00;
        d3=d3&0x0fffffff;
        d5=d5>>0xd;
        d4=d4>>0x14;
        d6=DESKEY3[d5];
        d5=d1&0xc0;
        d4=DESKEY4[d4];
        d5=(d5|d2)>>6;
        d4=d4|d6;
        d2=d1&0x3f;
        d6=DESKEY2[d5];
        d5=d3&0x180;
        d4=d4|d6;
        d6=DESKEY1[d2];
        d2=d3>>1;
        d4=d4|d6;
        d6=d2&0x1e00;
        d2=d2&0x6000000;
        d5=(d5^d6)>>7;
        d6=(d3&0x1e00000)|d2;
        d6=d6>>0x15;
        d2=DESKEY6[d5];
        d5=DESKEY8[d6];
        d2=d2^d5;
        d5=d3&0x3f;
        d6=DESKEY5[d5];
        d5=(d3>>0xf)&0x3f;
        d2=d2|d6;
        d6=DESKEY7[d5];
        d5=d4&0xffff;
        d2=d2|d6;
        d6=d2<<0x10;
        d2=d2&0xffff0000;
        d5=d5|d6;
        d5=(d5<<2)|(d5>>0x1e);
        d4=d4>>0x10;
        d2=d2|d4;
        d2=(d2<<6)|(d2>>0x1a);
        *(DWORD *)(desecb+8*i)=d5;
        *(DWORD *)(desecb+8*i+4)=d2;
    }
}

void des(unsigned char * LM,char * magic,unsigned char * ecb,long no)
{
    DWORD d1,d2,d3,d4;
    DWORD a1,a2,a3;
    int i;
    d1= *(DWORD *)magic;
    d2= *(DWORD *)(magic+4);
    d1 = (d1<<4)|(d1>>0x1c);
    d3 = d1;
    d1 = (d1^d2)&0xf0f0f0f0;
    d3 = d3^d1;
    d2 = d2^d1;
    d2 =(d2<<0x14)|(d2>>0xc);
    d1 = d2;
    d2 = (d2^d3)&0xfff0000f;
    d1 = d1 ^ d2;
    d3 = d3^d2;
    d1 = (d1<<0xe)|(d1>>0x12);
    d2 = d1;
    d1 = (d1 ^ d3) & 0x33333333;
    d2 = d2 ^ d1;
    d3 = d3^d1;
    d3 = (d3<<0x16)|(d3>>0xa);
    d1 = d3;
    d3 = (d3 ^ d2)&0x3fc03fc;
    d1 = d1^d3;
    d2 = d2^d3;
    d1 = (d1<<9)|(d1>>0x17);
    d3 = d1;
    d1 = (d1^d2)&0xaaaaaaaa;
    d3 = d3^d1;
    d2 = d2^d1;
    d2 = (d2<<1)|(d2>>0x1f);
    if(no!=0)
    {
        for(i=0;i<8;i++)
        {
            a1=0;
            d1=*(DWORD *)(ecb+16*i);
            d4=*(DWORD *)(ecb+16*i+4);
            d1=(d1^d3)&0xfcfcfcfc;
            d4=(d4^d3)&0xcfcfcfcf;
            a1=d1&0xff;
            a2=(d1>>8)&0xff;
            d4=(d4>>4)|(d4<<0x1c);
            a3=DESSpBox1[a1/4];
            a1=d4&0xff;
            d2=d2^a3;
            a3=DESSpBox3[a2/4];
            d2=d2^a3;
            a2=(d4>>8)&0xff;
            d1=d1>>0x10;
            a3=DESSpBox2[a1/4];
            d2=d2^a3;
            a1=(d1>>8)&0xff;
            d4=d4>>0x10;
            a3=DESSpBox4[a2/4];
            d2=d2^a3;
            a2=(d4>>8)&0xff;
            d1=d1&0xff;
            d4=d4&0xff;
            a1=DESSpBox7[a1/4];
            d2=d2^a1;
            a1=DESSpBox8[a2/4];
            d2=d2^a1;
            a1=DESSpBox5[d1/4];
            d2=d2^a1;
            a1=DESSpBox6[d4/4];
            d2=d2^a1;

            a1=0;
            d1=*(DWORD *)(ecb+16*i+8);
            d4=*(DWORD *)(ecb+16*i+0xc);
            d1=(d1^d2)&0xfcfcfcfc;
            d4=(d4^d2)&0xcfcfcfcf;
            a1=d1&0xff;
            a2=(d1>>8)&0xff;
            d4=(d4>>4)|(d4<<0x1c);
            a3=DESSpBox1[a1/4];
            a1=d4&0xff;
            d3=d3^a3;
            a3=DESSpBox3[a2/4];
            d3=d3^a3;
            a2=(d4>>8)&0xff;
            d1=d1>>0x10;
            a3=DESSpBox2[a1/4];
            d3=d3^a3;
            a1=(d1>>8)&0xff;
            d4=d4>>0x10;
            a3=DESSpBox4[a2/4];
            d3=d3^a3;
            a2=(d4>>8)&0xff;
            d1=d1&0xff;
            d4=d4&0xff;
            a1=DESSpBox7[a1/4];
            d3=d3^a1;
            a1=DESSpBox8[a2/4];
            d3=d3^a1;
            a1=DESSpBox5[d1/4];
            d3=d3^a1;
            a1=DESSpBox6[d4/4];
            d3=d3^a1;
        }
        d3=(d3>>1)|(d3<<0x1f);
        d1=d2;
        d2=(d2^d3)&0XAAAAAAAA;
        d1=d1^d2;
        d3=d3^d2;
        d1=(d1<<0x17)|(d1>>9);
        d2=d1;
        d1=(d1^d3)&0x3fc03fc;
        d2=(d2^d1);
        d3=d3^d1;
        d2=(d2<<0xa)|(d2>>0x16);
        d1=d2;
        d2=(d2^d3)&0x33333333;
        d1=d1^d2;
        d3=d3^d2;
        d3=(d3<<0x12)|(d3>>0xe);
        d2=d3;
        d3=(d3^d1)&0xfff0000f;
        d2=d2^d3;
        d1=d1^d3;
        d2=(d2<<0xc)|(d2>>0x14);
        d3=d2;
        d2=(d2^d1)&0xf0f0f0f0;
        d3=d3^d2;
        d1=d1^d2;
        d1=(d1>>4)|(d1<<0x1c);
        *(DWORD *)LM=d1;
        *(DWORD *)(LM+4)=d3;
    }
    else
    {
    }
}

void md5init(unsigned char * LM)
{
    memset(LM,0,0x58);
    *(DWORD *)(LM+8)=0x67452301;
    *(DWORD *)(LM+0xc)=0xefcdab89;
    *(DWORD *)(LM+0x10)=0x98badcfe;
    *(DWORD *)(LM+0x14)=0x10325476;
    *(DWORD *)(LM+0x0)=0;
    *(DWORD *)(LM+0x0)=0;
}

void md5final(unsigned char * LM)
{
    DWORD a1,d1,d2,s1;
    DWORD b1,b2;
    d1=*(DWORD *)(LM+0XC);
    s1=*(DWORD *)(LM+0X10);
    d2=*(DWORD *)(LM+0X14);
    b2=*(DWORD *)(LM+0X18);
    b1=(((d2^s1)&d1)^d2)+b2;
    b2=*(DWORD *)(LM+0X8);
    b1=b1+b2+0xd76aa478;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    //第一轮
    b2=*(DWORD *)(LM+0X1c);    
    a1=(((s1^d1)&b1)^s1)+0xe8c7b756;
    d2=d2+b2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    b2=*(DWORD *)(LM+0X20);    
    a1=(((d1^b1)&d2)^d1)+0x242070db;
    s1=s1+b2+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    b2=*(DWORD *)(LM+0X24);    
    a1=(((d2^b1)&s1)^b1)+0xc1bdceee;
    d1=d1+b2+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    b2=*(DWORD *)(LM+0X28);    
    a1=(((d2^s1)&d1)^d2)+0xf57c0faf;
    b1=b1+b2+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    b2=*(DWORD *)(LM+0X2c);    
    a1=(((s1^d1)&b1)^s1)+0x4787C62A;
    d2=d2+b2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;    
    b2=*(DWORD *)(LM+0X30);    
    a1=(((d1^b1)&d2)^d1)+0xA8304613;
    s1=s1+b2+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;    
    b2=*(DWORD *)(LM+0X34);    
    a1=(((d2^b1)&s1)^b1)+0xFD469501;
    d1=d1+b2+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;    
    b2=*(DWORD *)(LM+0X38);    
    a1=(((d2^s1)&d1)^d2)+0x698098D8;
    b1=b1+b2+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    b2=*(DWORD *)(LM+0X3c);    
    a1=(((s1^d1)&b1)^s1)+0x8B44F7AF;
    d2=d2+b2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    b2=*(DWORD *)(LM+0X40);    
    a1=(((d1^b1)&d2)^d1)+0xFFFF5BB1;
    s1=s1+b2+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    b2=*(DWORD *)(LM+0X44);    
    a1=(((d2^b1)&s1)^b1)+0x895CD7BE;
    d1=d1+b2+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    b2=*(DWORD *)(LM+0X48);    
    a1=(((d2^s1)&d1)^d2)+0x6B901122;
    b1=b1+b2+a1;
    b1=((b1<<0x7)|(b1>>0x19))+d1;
    b2=*(DWORD *)(LM+0X4c);    
    a1=(((s1^d1)&b1)^s1)+0xFD987193;
    d2=d2+b2+a1;
    d2=((d2<<0xc)|(d2>>0x14))+b1;
    b2=*(DWORD *)(LM+0X50);    
    a1=(((d1^b1)&d2)^d1)+0xA679438E;
    s1=s1+b2+a1;
    s1=((s1<<0x11)|(s1>>0xf))+d2;
    b2=*(DWORD *)(LM+0X54);    
    a1=(((d2^b1)&s1)^b1)+0x49B40821;
    d1=d1+b2+a1;
    d1=((d1<<0x16)|(d1>>0xa))+s1;
    //第二轮
    b2=*(DWORD *)(LM+0X1c);    
    a1=(((s1^d1)&d2)^s1)+0xF61E2562;
    b1=b1+b2+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    b2=*(DWORD *)(LM+0X30);    
    a1=(((d1^b1)&s1)^d1)+0xC040B340;
    d2=d2+b2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    b2=*(DWORD *)(LM+0X44);    
    a1=(((d2^b1)&d1)^b1)+0x265E5A51;
    s1=s1+b2+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    b2=*(DWORD *)(LM+0X18);    
    a1=(((d2^s1)&b1)^d2)+0xE9B6C7AA;
    d1=d1+b2+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    b2=*(DWORD *)(LM+0X2c);    
    a1=(((s1^d1)&d2)^s1)+0xD62F105D;
    b1=b1+b2+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    b2=*(DWORD *)(LM+0X40);    
    a1=(((d1^b1)&s1)^d1)+0x2441453;
    d2=d2+b2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    b2=*(DWORD *)(LM+0X54);    
    a1=(((d2^b1)&d1)^b1)+0xD8A1E681;
    s1=s1+b2+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    b2=*(DWORD *)(LM+0X28);    
    a1=(((d2^s1)&b1)^d2)+0xE7D3FBC8;
    d1=d1+b2+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    b2=*(DWORD *)(LM+0X3c);    
    a1=(((s1^d1)&d2)^s1)+0x21E1CDE6;
    b1=b1+b2+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    b2=*(DWORD *)(LM+0X50);    
    a1=(((d1^b1)&s1)^d1)+0xC33707D6;
    d2=d2+b2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    b2=*(DWORD *)(LM+0X24);    
    a1=(((d2^b1)&d1)^b1)+0xF4D50D87;
    s1=s1+b2+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    b2=*(DWORD *)(LM+0X38);    
    a1=(((d2^s1)&b1)^d2)+0x455A14ED;
    d1=d1+b2+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    b2=*(DWORD *)(LM+0X4c);    
    a1=(((s1^d1)&d2)^s1)+0xA9E3E905;
    b1=b1+b2+a1;
    b1=((b1<<0x5)|(b1>>0x1b))+d1;
    b2=*(DWORD *)(LM+0X20);    
    a1=(((d1^b1)&s1)^d1)+0xFCEFA3F8;
    d2=d2+b2+a1;
    d2=((d2<<0x9)|(d2>>0x17))+b1;
    b2=*(DWORD *)(LM+0X34);    
    a1=(((d2^b1)&d1)^b1)+0x676F02D9;
    s1=s1+b2+a1;
    s1=((s1<<0xe)|(s1>>0x12))+d2;
    b2=*(DWORD *)(LM+0X48);    
    a1=(((d2^s1)&b1)^d2)+0x8D2A4C8A;
    d1=d1+b2+a1;
    d1=((d1<<0x14)|(d1>>0xc))+s1;
    //第三轮
    b2=*(DWORD *)(LM+0X2c);    
    a1=((d2^s1)^d1)+0xFFFA3942;
    b1=b1+b2+a1;
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    b2=*(DWORD *)(LM+0X38);    
    a1=((s1^d1)^b1)+0x8771F681;
    d2=d2+b2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    b2=*(DWORD *)(LM+0X44);    
    a1=(d2^d1)^b1;
    s1=s1+b2+0x6D9D6122+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    b2=*(DWORD *)(LM+0X50);    
    a1=d2^s1;
    d1=d1+b2+0xFDE5380C+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    b2=*(DWORD *)(LM+0X1c);    
    b1=b1+b2+0xA4BEEA44+(d1^a1);
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    b2=*(DWORD *)(LM+0X28);    
    a1=((s1^d1)^b1)+0x4BDECFA9;
    d2=d2+b2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    b2=*(DWORD *)(LM+0X34);    
    a1=(d2^d1)^b1;
    s1=s1+b2+0xF6BB4B60+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    b2=*(DWORD *)(LM+0X40);    
    a1=(d2^s1);
    d1=d1+b2+0xBEBFBC70+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    b2=*(DWORD *)(LM+0X4c);    
    b1=b1+b2+0x289B7EC6+(d1^a1);
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    b2=*(DWORD *)(LM+0X18);    
    a1=((s1^d1)^b1)+0xEAA127FA;
    d2=d2+b2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    b2=*(DWORD *)(LM+0X24);    
    a1=(d2^d1)^b1;
    s1=s1+b2+0xD4EF3085+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    b2=*(DWORD *)(LM+0X30);    
    a1=d2^s1;
    d1=d1+b2+0x4881D05+(b1^a1);
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    b2=d1^a1;
    a1=*(DWORD *)(LM+0X3c)+0xD9D4D039;    
    b1=b1+b2+a1;
    b1=((b1<<0x4)|(b1>>0x1c))+d1;
    b2=*(DWORD *)(LM+0X48);
    a1=((s1^d1)^b1)+0xE6DB99E5;
    d2=d2+b2+a1;
    d2=((d2<<0xb)|(d2>>0x15))+b1;
    b2=*(DWORD *)(LM+0X54);
    a1=((d2^d1)^b1);
    s1=s1+b2+0x1FA27CF8+a1;
    s1=((s1<<0x10)|(s1>>0x10))+d2;
    b2=*(DWORD *)(LM+0X20);
    a1=((d2^s1)^b1);
    d1=d1+b2+0xC4AC5665+a1;
    d1=((d1<<0x17)|(d1>>0x9))+s1;
    //4
    b2=*(DWORD *)(LM+0X18);
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0xF4292244;
    b1=b1+b2+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    b2=*(DWORD *)(LM+0X34);
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0x432AFF97;
    d2=d2+b2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    b2=*(DWORD *)(LM+0X50);
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xAB9423A7;
    s1=s1+b2+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    b2=*(DWORD *)(LM+0X2c);
    a1=(((b1^0xFFFFFFFF)|s1)^d2);
    d1=d1+b2+0xFC93A039+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    b2=*(DWORD *)(LM+0X48);
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0x655B59C3;
    b1=b1+b2+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    b2=*(DWORD *)(LM+0X24);
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0x8F0CCC92;
    d2=d2+b2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    b2=*(DWORD *)(LM+0X40);
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xFFEFF47D;
    s1=s1+b2+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    b2=*(DWORD *)(LM+0X1c);
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0x85845DD1;
    d1=d1+b2+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    b2=*(DWORD *)(LM+0X38);
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0x6FA87E4F;
    b1=b1+b2+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    b2=*(DWORD *)(LM+0X54);
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0xFE2CE6E0;
    d2=d2+b2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    b2=*(DWORD *)(LM+0X30);
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0xA3014314;
    s1=s1+b2+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    b2=*(DWORD *)(LM+0X4c);
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0x4E0811A1;
    d1=d1+b2+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;
    b2=*(DWORD *)(LM+0X28);
    a1=(((d2^0xFFFFFFFF)|d1)^s1)+0xF7537E82;
    b1=b1+b2+a1;
    b1=((b1<<0x6)|(b1>>0x1a))+d1;
    b2=*(DWORD *)(LM+0X44);
    a1=(((s1^0xFFFFFFFF)|b1)^d1)+0xBD3AF235;
    d2=d2+b2+a1;
    d2=((d2<<0xa)|(d2>>0x16))+b1;
    b2=*(DWORD *)(LM+0X20);
    a1=(((d1^0xFFFFFFFF)|d2)^b1)+0x2AD7D2BB;
    s1=s1+b2+a1;
    s1=((s1<<0xf)|(s1>>0x11))+d2;
    b2=*(DWORD *)(LM+0X3c);
    a1=(((b1^0xFFFFFFFF)|s1)^d2)+0xEB86D391;
    d1=d1+b2+a1;
    d1=((d1<<0x15)|(d1>>0xb))+s1;

    b2=*(DWORD *)(LM+0X8);
    b1=b1+b2;
    b2=*(DWORD *)(LM+0Xc);
    d1=d1+b2;
    b2=*(DWORD *)(LM+0X10);
    s1=s1+b2;
    b2=*(DWORD *)(LM+0X14);
    d2=d2+b2;
    *(DWORD *)(LM+0X8)=b1;
    *(DWORD *)(LM+0Xc)=d1;
    *(DWORD *)(LM+0X10)=s1;
    *(DWORD *)(LM+0X14)=d2;
}


SMBNTLM认证过程与NTLM挑战的编程实现

http://www.cnblogs.com/huqingyu/archive/2008/02/17/1071632.html

创建时间:2003-05-16
文章属性:原创
文章提交:
flashsky (flashsky1_at_sina.com)

转摘请注明作者和安全焦点
作者:FLASHSKY
SITE
WWW.XFOCUS.NETWWW.SHOPSKY.COM
src:
 http://www.xfocus.net/articles/200305/533.html
邮件:flashsky@xfocus.org
                    
    //注:本文不涉及到NTLM具体的认证算法,但是给出通过SSPIAPI实现的过程。
    SMB协议可以说是WIN系统的核心协议,这里大致给大家讲解一下SMB认证登陆的过程:
    1。协议解析栈
    CLIENTAPP----->NET/MRP/RPC API------>MRXSMB.SYS------>NETBT.SYS---->TCP/IP
                                                           
    SERVER SRV.SYS<-----------MRXSMB.SYS<----------NETBT.SYS<--------TCP/IP
   
     应用程序调用NET/MPR/RPCAPI将信息写入WKSSVC管道,这个管道是一个特殊的管道,对应的其实是一个LPC端口。
     MRXSMB.SYS是一个SMB的小端口驱动,负责完成客户端的SMB的封装和实现,如发起协商,认证的加密/解密过程等。对于服务器端则主要
完成会话状态的一些管理,然后将SMB包发送给下级驱动处理。
     NETBT.SYSNETBIOS OVER TCP/IP的驱动,一般都是作为MRXSMB的下级驱动,不过MRXSMB也可以有其他的下级驱动,最后通过一个网络驱
动实现通讯,这里假设是使用TCP/IP
     SRV.SYS是服务器端的SMB协议驱动程序,实现完成真正的SMB的协议功能,然后将结果按原路返回给客户端。

    2SMB的认证协议。
    通过SMB进行认证客户端一般都要先使用SMB的协商命令(0X72)发送客户端支持的认证协议给服务器,服务器则选择其中的一个,然后返回
给客户端,客户端然后再使用SMB的会话设置和X命令(0X73)进行认证和登陆。
    MSSMB已经使用的SMB认证协议有:
      协议                        备注
    PC NETWORK PROGRAM 1.0                W2K支持                 
    PCLAN1.0                        W2K支持
    MICROSOFT NETWORKS 1.03                W2K支持
    MICROSOFT NETWORKS 3.0                W2K支持
    LANMAN1.0                        W2K支持
    DOS LM1.2X002                    W2K支持
    Windows for Workgroups 3.1a             W2K不支持,老的Windows for Workgroups 3.1使用此协议方式。
    LM1.2X002                        W2K支持   
    DOS LANMAN2.1                    W2K支持
    LANMAN2.1                        W2K支持
    NT LM 0.12                        W2K支持
    Cairo 0.xa                        W2K支持,这是NTMS自己开发的一个认证协议
    
    这里我们首先讲讲大家用的最多和最熟悉的NTLM认证方式:

    3NTLM认证过程
    NTLM在发展的过程中也存在这兼容的一些问题,现在的NTLM是支持挑战方式的,但原始的W9XNTLM则不支持挑战会话方式的,所以
从协议过程来看存在2种方式,一种是支持挑战加密的方式(NT2K等),一种是不支持加密挑战的方式(W9X)。
    i.    认证过程1
?    (客户端发起:会话协商协议)包含支持NTLM认证的选项且支持挑战选项。
?     (服务器:会话协商协议)选择了NTLM认证协议,且包含服务器的GUID
?    (客户端发起:会话设置和X协议)申请挑战会话的安全BLOB
?    (服务器:会话设置和X协议)返回带有挑战KEY的安全BLOB
?    (客户端发起:会话设置和X协议)带会话KEY加密的口令散列的安全BLOB
?        认证成功:会话设置和X协议返回成功信息
        认证失败:会话设置和X协议返回失败信息,发起注销协议包
    ii.    认证过程2
?    (客户端发起:会话协商协议)包含支持NTLM认证的选项且不支持挑战选项。
?     (服务器:会话协商协议)选择了NTLM认证协议,且包含会话KEY
?    (客户端发起:会话设置和X协议)使用会话KEY加密的密码散列
//注意可以指定是非加密方式的密码明文来进行登陆
?    认证成功:会话设置和X协议返回成功信息
    认证失败:会话设置和X协议返回失败信息,发起注销协议包

    我们这里主要讲认证过程1,其实过程2一般为很多工具使用,因为可以通过特定的FLAG字段指定不使用挑战和加密方式进行登陆,
那么就可以方便的使用明文口令,如SMBCRACK主要使用这种方法进行口令暴力破解,但是需要注意的一点是,这种属于老的方式,是可以在
服务器端禁止的。
    客户端APP通过写入WKSSVC管道(LPC端口发起)相关命令和数据
        客户端MRXSMB.SYSSmbCeNegotiate函数负责进行协商包的封装并交下级驱动封装
        服务器SRV.SYSSrvSmbNegotiate函数负责选取一个认证协议并返回给客户端,并返回服务器的GUID
    客户端的MRXSMB.SYSSmbCeReferenceSession负责进行认证:
模拟过程函数如下:

BYTE buf1[0x404c];
TOKEN_STATISTICS ts;
CredHandle phs;
CredHandle phc;
CtxtHandle cthc;
CtxtHandle cths;
SECURITY_STATUS   ss;
wchar_t TargetName[]=L"HOST/192.168.0.34";
int len;

typedef struct _Credentials
{
    char * pusername;
    DWORD usernamelen;
    char * pdomainname;
    DWORD domainnamelen;
    char * ppassword;
    DWORD passwordlen;
    DWORD credtype;
    BYTE info[0x200];
}Credentials,* PCredentials;

void client1()
{
    Credentials crt;
    LUID LogonID;
    HANDLE tk;
    TimeStamp Lifetime;
    DWORD ContextAttributes;
    DWORD rlen;
    char crtinfo[]={'a',0,'d',0,'m',0,'i',0,'n',0,'i',0,'s',0,'t',0,'r',0,'a',0,'t',0,'o',0,'r',0,0,0,'p',0,'s',0,'w',0,'d',0,0,0};
    
    SecBufferDesc     OutBuffDesc;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    SecBuffer         OutSecBuff;
    LogonID.HighPart =0;
    LogonID.LowPart = 0x7d80;

    //输入的口令在此需要CRT
    //自动的则不需要
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tk);
    GetTokenInformation(tk,TokenStatistics,&ts,sizeof(ts),&rlen);
    crt.pusername = crt.info;
    crt.usernamelen = 0xd;
    crt.pdomainname =0;
    crt.domainnamelen = 0;
    crt.ppassword = crt.info+0x1c;
    crt.passwordlen =4;
    crt.credtype = 6;
    memcpy(crt.info,crtinfo,0x22); 

    ss=AcquireCredentialsHandleW
        (NULL,L"Negotiate",SECPKG_CRED_OUTBOUND,&ts.AuthenticationId,&crt,NULL,NULL,&phc,&Lifetime);

    InBuffDesc.ulVersion = 0;
    InBuffDesc.cBuffers = 1;
    InBuffDesc.pBuffers = &InSecBuff;
    InSecBuff.BufferType =SECBUFFER_TOKEN;
    InSecBuff.cbBuffer =0;
    InSecBuff.pvBuffer = buf1;
    OutBuffDesc.ulVersion = 0;
    OutBuffDesc.cBuffers = 1;
    OutBuffDesc.pBuffers = &OutSecBuff;
    OutSecBuff.BufferType = SECBUFFER_TOKEN;
    OutSecBuff.cbBuffer =0x404c;
    OutSecBuff.pvBuffer = buf1;
    ss=InitializeSecurityContextW(
            &phc,
            NULL,
            TargetName,
            ASC_REQ_MUTUAL_AUTH|ASC_REQ_DELEGATE|ASC_REQ_STREAM|ASC_REQ_ALLOW_NON_USER_LOGONS,//0x210003
            0,
            SECURITY_NATIVE_DREP,
        &InBuffDesc,
            0,
            &cthc,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );
    len=OutSecBuff.cbBuffer;
    
}
    解释:
    TargetName后面的192.168.0.34SMB服务器的名字,如果是用的IP就使用IP,用的NETBIOS名字就使用NETBIOS名字
    InitializeSecurityContextW之后的buf1里面就是BLOB数据。然后将此数据放于SMB包中的安全BLOB处进行传送。
    AcquireCredentialsHandle中的crt是当使用输入用户与口令的时候使用的,格式是明文和UNICODE的(参考Credentials结构)。当
系统使用SAM数据进行登陆的时候,此处可以是NULLNULL的时候和非NULL的时候生成的安全BLOB的头内容是不同的。
    ts.AuthenticationId是认证的LUID,其实MRXSMB使用的是WIN32K.sys的不对外的GetProcessLuid函数来获取的,这里使用
GetTokenInformation来进行模拟。当系统使用系统的SAM登陆时,必须获得此值,才知道使用的认证ID,当然如果你知道且能获得其他用户进
程的认证LUID,也可以使用,不仅仅非要是自己进程的认证LUID

    服务器的SRV.SYS获得此安全BLOB之后,调用SrvSmbSessionSetupAndX函数来进行处理,实际的处理函数是BlockingSessionSetupAndX函数。
调用SrvValidateSecurityBuffer,主要工作是根据客户端的初始BLOB生成带会话KEY的安全BLOB返回给客户端,模拟程序如下:

void server2()
{
    TimeStamp         Lifetime;
    SecBufferDesc     OutBuffDesc;
    SecBuffer         OutSecBuff;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    DWORD ContextAttributes;
    BYTE pOut[0X40DD];
    BYTE pIn[0X50];
    
    ss=AcquireCredentialsHandleW
        (NULL,L"Negotiate",SECPKG_CRED_INBOUND,NULL,NULL,NULL,NULL,&phs,&Lifetime);

   OutBuffDesc.ulVersion = 0;
   OutBuffDesc.cBuffers = 1;
   OutBuffDesc.pBuffers = &OutSecBuff;
   OutSecBuff.cbBuffer = 0x40dd;
   OutSecBuff.BufferType = SECBUFFER_TOKEN;
   OutSecBuff.pvBuffer = pOut;
   InBuffDesc.ulVersion = 0;
   InBuffDesc.cBuffers = 1;
   InBuffDesc.pBuffers = &InSecBuff;
   InSecBuff.cbBuffer = len;
   InSecBuff.BufferType = SECBUFFER_TOKEN;
   InSecBuff.pvBuffer = pIn;
   memset(pIn,0,0x40dd);
   memset(pOut,0,0x40dd);
   memcpy(pIn,buf1,0x10);

   ss=AcceptSecurityContext (
            &phs,
            NULL,
            &InBuffDesc,
            ASC_REQ_DELEGATE|ASC_REQ_EXTENDED_ERROR|ASC_REQ_FRAGMENT_TO_FIT, //ASC_REQ_ALLOW_NULL_SESSION
            0x10,//SECURITY_NATIVE_DREP,

            &cths,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );
    len=OutSecBuff.cbBuffer;
}

    解释:
    ASC_REQ_ALLOW_NULL_SESSION选项在用户模式下不可用,在SRV.SYS则可以使用
    实际上客户端生成的初始BLOB只有前0X10字节(BLOB头)是有意义的,AcceptSecurityContext执行后的pOut缓冲里就是需要返回的
带会话KEY的安全BLOB

    客户端的MRXSMB.SYS获得这个安全BLOB后就会使用此KEY进行加密。模拟的程序如下:
void client3()
{
    TimeStamp Lifetime;
    DWORD ContextAttributes;
    SecBufferDesc     OutBuffDesc;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    SecBuffer         OutSecBuff;

    InBuffDesc.ulVersion = 0;
    InBuffDesc.cBuffers = 1;
    InBuffDesc.pBuffers = &InSecBuff;
    InSecBuff.BufferType =SECBUFFER_TOKEN;
    InSecBuff.cbBuffer =len;
    InSecBuff.pvBuffer = buf1;
    OutBuffDesc.ulVersion = 0;
    OutBuffDesc.cBuffers = 1;
    OutBuffDesc.pBuffers = &OutSecBuff;
    OutSecBuff.BufferType = SECBUFFER_TOKEN;
    OutSecBuff.cbBuffer =0x404c;
    OutSecBuff.pvBuffer = buf1;
    ss=
(
            &phc,
            &cthc,
            TargetName,
            ASC_REQ_MUTUAL_AUTH|ASC_REQ_DELEGATE|ASC_REQ_STREAM|ASC_REQ_ALLOW_NON_USER_LOGONS,//0x210003
            0,
            SECURITY_NATIVE_DREP,
            &InBuffDesc,
            0,
            &cthc,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );
}
    
    在这个生成的过程中一些特性:
    我们使用同一返回的KEY,每次生成的认证内容都不一样,但是每次都是可以被认证的,那么我们可以得出一个结论,在这个认证的
    信息里还包含有时间戳或其他随机生成数据,加密和解密的算法还使用到了这个数据,这个数据也在认证内容中一起被发送到服务器。

服务器端进行认证的代码
void server4()
{
    TimeStamp         Lifetime;
    SecBufferDesc     OutBuffDesc;
    SecBuffer         OutSecBuff;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    DWORD ContextAttributes;
    

   OutBuffDesc.ulVersion = 0;
   OutBuffDesc.cBuffers = 1;
   OutBuffDesc.pBuffers = &OutSecBuff;
   OutSecBuff.cbBuffer = 0x40dd;
   OutSecBuff.BufferType = SECBUFFER_TOKEN;
   OutSecBuff.pvBuffer = buf1;
   InBuffDesc.ulVersion = 0;
   InBuffDesc.cBuffers = 1;
   InBuffDesc.pBuffers = &InSecBuff;
   InSecBuff.cbBuffer = len;
   InSecBuff.BufferType = SECBUFFER_TOKEN;
   InSecBuff.pvBuffer = buf1;


   ss=AcceptSecurityContext (
            &phs,
            &cths,
            &InBuffDesc,
            ASC_REQ_DELEGATE|ASC_REQ_EXTENDED_ERROR|ASC_REQ_FRAGMENT_TO_FIT, //ASC_REQ_ALLOW_NULL_SESSION
            0x10,//SECURITY_NATIVE_DREP,
            &cths,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );
    if(ss==SEC_E_OK)
        printf("ok");
    else
        printf("error");
    
}
    
4.挑战NTLM的编程实现
        那么我们就可以实现一个纯TCP/IPSMB使用NTLM的挑战方式进行登陆了,再这之前大家需要了解SMB协议,这里由于涉及到
公司的商业利益,我不能给予大家最详细的协议说明,但从程序代码和其中的注解大家应该大致知道。这个程序大家修改一下就可以
得到类似SMBCRACK功能的口令破解的多线程支持NTLM挑战方式的(这样可以使用在标准的W2K认可的方式,关闭了非挑战和不许可明
文口令方式登陆的W2K服务器)的工具,但是由于口令计算的消耗,速度就会慢一些:
SMB.h文件:
#include <windows.h>

typedef struct _SMBNBT
{
    unsigned char nbtsmb;
    unsigned char flag;
    short smbpacketlen;
}SMBNBT,* PSMBNBT;

typedef struct _SMBINFO
{
    unsigned char magic[4];
    BYTE smbtoken;
    BYTE errcodeclass;
    BYTE dosaherrcode;
    unsigned char errcode[2];
    BYTE flagsummary;
    short flagsummary2;
    short unuse[6];
    short treeid;
    short callprocessid;
    short userid;
    short multiplexid;
    unsigned char info[2048];
}SMBINFO,* PSMBINFO;

typedef struct _SMBP
{
    SMBNBT smbnbt;
    SMBINFO smbinfo;
}SMBP,* PSMBP;

typedef struct _Credentials
{
    char * pusername;
    DWORD usernamelen;
    char * pdomainname;
    DWORD domainnamelen;
    char * ppassword;
    DWORD passwordlen;
    DWORD credtype;
    BYTE info[0x200];
}Credentials,* PCredentials;
    
客户端程序:

#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <wincrypt.h>
#include <process.h>
#include <string.h>
#include <winbase.h>
# include <wincrypt.h>
#define SECURITY_WIN32
# include <Security.h>
#include "SMB.H"

void SmbNegotiate(SMBP * psmbp);
void SmbSessionSetupAndX1(SMBP * psmbp,wchar_t * username,wchar_t * domainname,wchar_t * password);
void SmbSessionSetupAndX2(SMBP * psmbp,unsigned char * ntlmrcv,short ntlmlen);

TOKEN_STATISTICS ts;
CredHandle phs;
CredHandle phc;
CtxtHandle cthc;
CtxtHandle cths;
SECURITY_STATUS   ss;
wchar_t TargetName[]=L"HOST/192.168.13.34";//后面的192.168.0.34SMB服务器的名字,如果是用的IP就使用IP,用的NETBIOS名字就使用NETBIOS名字)
wchar_t navos[]=L"windows 2000 2195";
wchar_t lanman[]=L"windows 2000 5.0";

void main(int argc,char ** argv)
{
    WSADATA WSAData;
    int i;
    SOCKET sock;
    SOCKADDR_IN addr_in;
    int len;
    char serverip[]="192.168.13.34";
    short port=445;
    WORD olen,nlen;
    unsigned char buf1[0x1000];
    SMBP smbp;

    if (WSAStartup(MAKEWORD(2,0),&WSAData)!=0)
    {
        printf("WSAStartup error.Error:%d\n",WSAGetLastError());
        return;
    }

    addr_in.sin_family=AF_INET;
    addr_in.sin_port=htons(port);
    addr_in.sin_addr.S_un.S_addr=inet_addr(serverip);
    
    if ((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
    {
        printf("Socket failed.Error:%d\n",WSAGetLastError());
        return;
    }
    if(WSAConnect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in),NULL,NULL,NULL,NULL)==SOCKET_ERROR)
    {
        printf("Connect failed.Error:%d",WSAGetLastError());
        return;
    }
    SmbNegotiate(&smbp);
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    SmbSessionSetupAndX1(&smbp,L"administrator",L"",L"1972");
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    if((buf1[0]==0xff)&&(buf1[1]=='S')&&(buf1[2]=='M')&&(buf1[3]=='B'))
        olen=0x20;
    else if((buf1[4]==0xff)&&(buf1[5]=='S')&&(buf1[6]=='M')&&(buf1[7]=='B'))
        olen=0x24;
    else
        return;
    smbp.smbinfo.userid =  *(WORD *)(buf1+olen-0x4);
    nlen=*(WORD *)(buf1+olen+1+2*3);//BLOB的长度
    olen=olen+1+2*buf1[olen]+2;
    SmbSessionSetupAndX2(&smbp,buf1+olen,nlen);
    if (send(sock,(unsigned char *)&smbp,ntohs(smbp.smbnbt.smbpacketlen)+4,0)==SOCKET_ERROR)
    {
            printf("Send failed.Error:%d\n",WSAGetLastError());
            return;
    }
    len=recv(sock,buf1,1024,NULL);
    if((buf1[0]==0xff)&&(buf1[1]=='S')&&(buf1[2]=='M')&&(buf1[3]=='B'))
        olen=0x20;
    else if((buf1[4]==0xff)&&(buf1[5]=='S')&&(buf1[6]=='M')&&(buf1[7]=='B'))
        olen=0x24;
    else
        return;
    if(buf1[olen]==0)
        printf("error username and password\n");
    else
        printf("login ok\n");
    WSACleanup();
    return;
}

void SmbSessionSetupAndX1(SMBP * psmbp,wchar_t * username,wchar_t * domainname,wchar_t * password)
{
    LUID LogonID;
    unsigned char buf1[0x404c];
    HANDLE tk;
    TimeStamp Lifetime;
    DWORD ContextAttributes;
    DWORD rlen;
    DWORD r1,r2,r3;
    int i;
    Credentials crt;
    SecBufferDesc     OutBuffDesc;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    SecBuffer         OutSecBuff;
    LogonID.HighPart =0;
    LogonID.LowPart = 0x7d80;

    psmbp->smbinfo.smbtoken =0x73; 
    memset(psmbp->smbinfo.info,0,0x200); 
    psmbp->smbinfo.flagsummary2 = 0xc807;
    *(DWORD *)(psmbp->smbinfo.info+21) = 0x800000D4;
    //指定使用加密的FLAG
    psmbp->smbinfo.info[0]=0xc;//WORD 参数个数
    *(WORD *)(psmbp->smbinfo.info+1)=0Xff;//无下一个命令
    *(WORD *)(psmbp->smbinfo.info+3)=0Xb0;//下一命令偏移
    *(WORD *)(psmbp->smbinfo.info+5)=0X4104;//最大缓冲
    *(WORD *)(psmbp->smbinfo.info+7)=0X32;//最大的MPX
    *(WORD *)(psmbp->smbinfo.info+9)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+11)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+17)=0X0;//保留

    //输入的口令在此需要CRT
    //自动的则不需要
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tk);
    GetTokenInformation(tk,TokenStatistics,&ts,sizeof(ts),&rlen);
    r1=0;
    for(i=0;i<0x30;i++)
    {
        if(username[i]==0)
            break;
        r1=r1+2;
    }
    r2=0;
    for(i=0;i<0x30;i++)
    {
        if(domainname[i]==0)
            break;
        r2=r2+2;
    }
    r3=0;
    for(i=0;i<0x30;i++)
    {
        if(password[i]==0)
            break;
        r3=r3+2;
    }
    crt.pusername = crt.info;
    crt.usernamelen = r1/2;
    if(r2>0)
    {
        crt.pdomainname =crt.info+r1+2;
        crt.domainnamelen = r2/2;
        crt.ppassword = crt.pdomainname+r2+2;
        crt.passwordlen =r3/2;
    }
    else
    {
        crt.pdomainname =0;
        crt.domainnamelen = 0;
        crt.ppassword = crt.info+r1+2;
        crt.passwordlen =r3/2;
    }
    crt.credtype = 6;
    memcpy(crt.pusername,username,r1); 
    if(r2>0)
        memcpy(crt.pdomainname,domainname,r2); 
    memcpy(crt.ppassword,password,r3); 
    ss=AcquireCredentialsHandleW
        (NULL,L"Negotiate",SECPKG_CRED_OUTBOUND,&ts.AuthenticationId,&crt,NULL,NULL,&phc,&Lifetime);
    //LOGIN会影响生成
    InBuffDesc.ulVersion = 0;
    InBuffDesc.cBuffers = 1;
    InBuffDesc.pBuffers = &InSecBuff;
    InSecBuff.BufferType =SECBUFFER_TOKEN;
    InSecBuff.cbBuffer =0;
    InSecBuff.pvBuffer = buf1;
    OutBuffDesc.ulVersion = 0;
    OutBuffDesc.cBuffers = 1;
    OutBuffDesc.pBuffers = &OutSecBuff;
    OutSecBuff.BufferType = SECBUFFER_TOKEN;
    OutSecBuff.cbBuffer =0x404c;
    OutSecBuff.pvBuffer = buf1;
    ss=InitializeSecurityContextW(
            &phc,
            NULL,
            TargetName,
            ASC_REQ_MUTUAL_AUTH|ASC_REQ_DELEGATE|ASC_REQ_STREAM|ASC_REQ_ALLOW_NON_USER_LOGONS,//0x210003
            0,
            SECURITY_NATIVE_DREP,
            &InBuffDesc,
            0,
            &cthc,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );

    *(WORD *)(psmbp->smbinfo.info+15)=OutSecBuff.cbBuffer;  //BLOB的长度
    memcpy(psmbp->smbinfo.info+27,buf1,OutSecBuff.cbBuffer);//放入BLOB
    memcpy(psmbp->smbinfo.info+28+OutSecBuff.cbBuffer,navos,36);//
    memcpy(psmbp->smbinfo.info+66+OutSecBuff.cbBuffer,lanman,32);//
    *(WORD *)(psmbp->smbinfo.info+25)=73+OutSecBuff.cbBuffer;
    psmbp->smbnbt.smbpacketlen = htons(132+ OutSecBuff.cbBuffer);
}

void SmbSessionSetupAndX2(SMBP * psmbp,unsigned char * ntlmrcv,short ntlmlen)
{
    TimeStamp Lifetime;
    DWORD ContextAttributes;
    SecBufferDesc     OutBuffDesc;
    SecBufferDesc     InBuffDesc;
    SecBuffer         InSecBuff;
    SecBuffer         OutSecBuff;
    unsigned char buf1[0x404c];

    psmbp->smbinfo.smbtoken =0x73; 
    memset(psmbp->smbinfo.info,0,0x200); 
    psmbp->smbinfo.flagsummary2 = 0xc807;
    *(DWORD *)(psmbp->smbinfo.info+21) = 0x800000D4;
    //指定使用加密的FLAG
    psmbp->smbinfo.info[0]=0xc;//WORD 参数个数
    *(WORD *)(psmbp->smbinfo.info+1)=0Xff;//无下一个命令
    *(WORD *)(psmbp->smbinfo.info+3)=0X12e;//下一命令偏移
    *(WORD *)(psmbp->smbinfo.info+5)=0X4104;//最大缓冲
    *(WORD *)(psmbp->smbinfo.info+7)=0X32;//最大的MPX
    *(WORD *)(psmbp->smbinfo.info+9)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+11)=0X0;//虚拟通道
    *(DWORD *)(psmbp->smbinfo.info+17)=0X0;//保留

    //输入的口令在此需要CRT
    //自动的则不需要
    InBuffDesc.ulVersion = 0;
    InBuffDesc.cBuffers = 1;
    InBuffDesc.pBuffers = &InSecBuff;
    InSecBuff.BufferType =SECBUFFER_TOKEN;
    InSecBuff.cbBuffer =ntlmlen;
    InSecBuff.pvBuffer = ntlmrcv;
    OutBuffDesc.ulVersion = 0;
    OutBuffDesc.cBuffers = 1;
    OutBuffDesc.pBuffers = &OutSecBuff;
    OutSecBuff.BufferType = SECBUFFER_TOKEN;
    OutSecBuff.cbBuffer =0x404c;
    OutSecBuff.pvBuffer = buf1;
    ss=InitializeSecurityContextW(
            &phc,
            &cthc,
            TargetName,
            ASC_REQ_MUTUAL_AUTH|ASC_REQ_DELEGATE|ASC_REQ_STREAM|ASC_REQ_ALLOW_NON_USER_LOGONS,//0x210003
            0,
            SECURITY_NATIVE_DREP,
            &InBuffDesc,
            0,
            &cthc,
            &OutBuffDesc,
            &ContextAttributes,
            &Lifetime
            );
    *(WORD *)(psmbp->smbinfo.info+15)=OutSecBuff.cbBuffer;  //BLOB的长度
    memcpy(psmbp->smbinfo.info+27,buf1,OutSecBuff.cbBuffer);//放入BLOB
    memcpy(psmbp->smbinfo.info+28+OutSecBuff.cbBuffer,navos,36);//
    memcpy(psmbp->smbinfo.info+66+OutSecBuff.cbBuffer,lanman,32);//
    *(WORD *)(psmbp->smbinfo.info+25)=73+OutSecBuff.cbBuffer;
    psmbp->smbnbt.smbpacketlen = htons(132+ OutSecBuff.cbBuffer);
}

void SmbNegotiate(SMBP * psmbp)
{
    unsigned char magic[4]={0xff,'S','M','B'};
    short len;
    char langitem1[]="PC NETWORK PROGRAM 1.0";
    char langitem2[]="LANMAN1.0";
    char langitem3[]="Windows for Workgroups 3.1a";
    char langitem4[]="LM1.2X002";
    char langitem5[]="LANMAN2.1";
    char langitem6[]="NT LM 0.12";
    char langitem7[]="PCLAN1.0";
    char langitem8[]="MICROSOFT NETWORKS 1.03";
    char langitem9[]="MICROSOFT NETWORKS 3.0";
    char langitem10[]="DOS LM1.2X002";
    char langitem11[]="DOS LANMAN2.1";
    char langitem12[]="Cairo 0.xa";

    memset(psmbp,0,sizeof(SMBP));
    psmbp->smbnbt.nbtsmb = 0;
    psmbp->smbnbt.flag = 0;
    memcpy(psmbp->smbinfo.magic, magic,4);
    psmbp->smbinfo.smbtoken = 0x72; 
    psmbp->smbinfo.errcodeclass = 0x0;
    psmbp->smbinfo.dosaherrcode = 0x0;
    psmbp->smbinfo.errcode[0] = 0x0;
    psmbp->smbinfo.errcode[1] = 0x0;
    psmbp->smbinfo.flagsummary = 0x18;
    psmbp->smbinfo.flagsummary2 = 0xc853;
    //指定了带挑战方式支持的FLAG
    psmbp->smbinfo.callprocessid = 0xfeff;
    psmbp->smbinfo.multiplexid = 0;
    psmbp->smbinfo.info[0]=0x0;
    len=3+2*(psmbp->smbinfo.info[0]);
    /*
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem3,sizeof(langitem3));
    len = len+1+sizeof(langitem3);
    
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem1,sizeof(langitem1));
    len = len+1+sizeof(langitem1);

    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem2,sizeof(langitem2));
    len = len+1+sizeof(langitem2);
    

    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem4,sizeof(langitem4));
    len = len+1+sizeof(langitem4);

    
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem5,sizeof(langitem5));
    len = len+1+sizeof(langitem5);
        
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem6,sizeof(langitem6));
    len = len+1+sizeof(langitem6);
    */
    psmbp->smbinfo.info[len]=0x2;
    memcpy(psmbp->smbinfo.info+len+1,langitem6,sizeof(langitem6));
    len = len+1+sizeof(langitem6);

    *(WORD *)(psmbp->smbinfo.info+1) =len-3-2*(psmbp->smbinfo.info[0]);
    psmbp->smbnbt.smbpacketlen = htons(len+0x20); 
}


深讨Java SE 6 HTTP 方面的新特性(NTLM)

http://www.cnblogs.com/huqingyu/archive/2008/02/17/1071629.html
【摘 要】 在 Java SE 6 当中,围绕着 HTTP 协议出现了很多实用的新特性:NTLM 认证提供了一种 Window 平台下较为安全的认证机制;JDK 当中提供了一个轻量级的 HTTP 服务器;提供了较为完善的 HTTP Cookie 管理功能;更为实用的 NetworkInterface;DNS 域名的国际化支持

   概述

  Java 语言从诞生的那天起,就非常注重网络编程方面的应用。随着互联网应用的飞速发展,Java 的基础类库也不断地对网络相关的 API 进行加强和扩展。在 Java SE 6 当中,围绕着 HTTP 协议出现了很多实用的新特性:NTLM 认证提供了一种 Window 平台下较为安全的认证机制;JDK 当中提供了一个轻量级的 HTTP 服务器;提供了较为完善的 HTTP Cookie 管理功能;更为实用的 NetworkInterface;DNS 域名的国际化支持等等。

      NTLM 认证

  不可避免,网络中有很多资源是被安全域保护起来的。访问这些资源需要对用户的身份进行认证。下面是一个简单的例子:

以下是引用片段:

import java.net.*;
import java.io.*;

public class Test {
 public static void main(String[] args) throws Exception {
  URL url = new URL("http://PROTECTED.com");
  URLConnection connection = url.openConnection();
  InputStream in = connection.getInputStream();
  byte[] data = new byte[1024];
  while(in.read(data)>0)
  {
   //do something for data
  }
  in.close();
 }
}

  当 Java 程序试图从一个要求认证的网站读取信息的时候,也就是说,从联系于 http://Protected.com 这个 URLConnection InputStream read 数据时,会引发 FileNotFoundException。尽管笔者认为,这个 Exception 的类型与实际错误发生的原因实在是相去甚远;但这个错误确实是由网络认证失败所导致的。

  要解决这个问题,有两种方法:

  其一,是给 URLConnection 设定一个"Authentication"属性:

以下是引用片段:

String credit = USERNAME + ":" + PASSWORD;
String encoding = new sun.misc.BASE64Encoder().encode (credit.getBytes());
connection.setRequestProperty ("Authorization", "Basic " + encoding);

  这里假设 http://PROTECTED.COM 使用了基本(Basic)认证类型。

从上面的例子,我们可以看出,设定 Authentication 属性还是比较复杂的:用户必须了解认证方式的细节,才能将用户名/密码以一定的规范给出,然后用特定的编码方式加以编码。Java 类库有没有提供一个封装了认证细节,只需要给出用户名/密码的工具呢?

  这就是我们要介绍的另一种方法,使用 java.net.Authentication 类。

  每当遇到网站需要认证的时候,HttpURLConnection 都会向 Authentication 类询问用户名和密码。

  Authentication 类不会知道究竟用户应该使用哪个 username/password 那么用户如何向 Authentication 类提供自己的用户名和密码呢?

  提供一个继承于 Authentication 的类,实现 getPasswordAuthentication 方法,在 PasswordAuthentication 中给出用户名和密码:

以下是引用片段:
class DefaultAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication () {
return new PasswordAuthentication ("USER", "PASSWORD".toCharArray());
}
}      

  然后,将它设为默认的(全局)Authentication:

以下是引用片段:
Authenticator.setDefault (new DefaultAuthenticator()); 

  那么,不同的网站需要不同的用户名/密码又怎么办呢?

  Authentication 提供了关于认证发起者的足够多的信息,让继承类根据这些信息进行判断,在 getPasswordAuthentication 方法中给出了不同的认证信息:

以下是引用片段:

  • getRequestingHost()
  • getRequestingPort()
  • getRequestingPrompt()
  • getRequestingProtocol()
  • getRequestingScheme()
  • getRequestingURL()
  • getRequestingSite()
  • getRequestorType()

  另一件关于 Authentication 的重要问题是认证类型。不同的认证类型需要 Authentication 执行不同的协议。至 Java SE 6.0 为止,Authentication 支持的认证方式有:

以下是引用片段:

  • HTTP Basic authentication
  • HTTP Digest authentication
  • NTLM
  • Http SPNEGO Negotiate

    • Kerberos
    • NTLM

NTLM NT LAN Manager 的缩写。早期的 SMB 协议在网络上明文传输口令,这是很不安全的。微软随后提出了 WindowsNT 挑战/响应验证机制,即 NTLM

  NTLM 协议是这样的:

  1.客户端首先将用户的密码加密成为密码散列;

  2.客户端向服务器发送自己的用户名,这个用户名是用明文直接传输的;

  3.服务器产生一个 16 位的随机数字发送给客户端,作为一个 challenge(挑战) ;

  4.客户端用步骤1得到的密码散列来加密这个 challenge ,然后把这个返回给服务器;

  5.服务器把用户名、给客户端的 challenge 、客户端返回的 response 这三个东西,发送域控制器 ;

  6.域控制器用这个用户名在 SAM 密码管理库中找到这个用户的密码散列,然后使用这个密码散列来加密 challenge;

  7.域控制器比较两次加密的 challenge ,如果一样,那么认证成功;

  Java 6 以前的版本,是不支持 NTLM 认证的。用户若想使用 HttpConnection 连接到一个使用有 Windows 域保护的网站时,是无法通过 NTLM 认证的。另一种方法,是用户自己用 Socket 这样的底层单元实现整个协议过程,这无疑是十分复杂的。

  终于,Java 6 Authentication 类提供了对 NTLM 的支持。使用十分方便,就像其他的认证协议一样:

以下是引用片段:

class DefaultAuthenticator extends Authenticator {
 private static String username = "username ";
 private static String domain =  "domain ";
 private static String password =  "password ";
  
 public PasswordAuthentication getPasswordAuthentication() {
  String usernamewithdomain = domain + "/ "+username;
  return (new PasswordAuthentication(usernamewithdomain, password.toCharArray()));
 }
}

  这里,根据 Windows 域账户的命名规范,账户名为域名+"/"+域用户名。如果不想每生成 PasswordAuthentication 时,每次添加域名,可以设定一个系统变量名"http.auth.ntlm.domain"。

  Java 6 Authentication 的另一个特性是认证协商。目前的服务器一般同时提供几种认证协议,根据客户端的不同能力,协商出一种认证方式。比如,IIS 服务器会同时提供 NTLM with kerberos NTLM 两种认证方式,当客户端不支持 NTLM with kerberos 时,执行 NTLM 认证。

  目前,Authentication 的默认协商次序是:

以下是引用片段:
GSS/SPNEGO -> Digest -> NTLM -> Basic  

  那么 kerberos 的位置究竟在哪里呢?

  事实上,GSS/SPNEGO JAAS 为基石,而后者实际上就是使用 kerberos 的。

  域名的国际化

  在最近的一些 RFC 文档当中,规定 DNS 服务器可以解析除开 ASCII 以外的编码字符。有一个算法可以在这种情况下做 Unicode ASCII 码之间的转换,实现域名的国际化。java.net.IDN 就是实现这个国际化域名转换的新类,IDN 是"国际化域名"的缩写(internationalized domain names)。这个类很简单,主要包括 4 个静态函数,做字符的转换。

      结语

  Java SE 6 有着很多 HTTP 相关的新特性,使得 Java SE 平台本身对网络编程,尤其是基于 HTTP 协议的因特网编程,有了更加强大的支持。


Java里面Windows的身份验证

http://www.cnblogs.com/huqingyu/archive/2008/02/17/1071641.html
Java里面去读取Windows域帐号,这样一个小的Web系统就不需要再建立一套帐户和密码了。
asp.net里面这个是很容易实现的,但是Java里面不知道该如何去取得呢?

<%
String auth = request.getHeader("Authorization");
if (auth == null)
{
response.setStatus(response.SC_UNAUTHORIZED);
response.setHeader("WWW-Authenticate", "NTLM");
response.flushBuffer();
return;
}
if (auth.startsWith("NTLM "))
{
byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
int off = 0, length, offset;
if (msg[8] == 1)
{
byte z = 0;
byte[] msg1 = {(byte)'N', (byte)'T', (byte)'L', (byte)'M', (byte)'S', (byte)'S', (byte)'P', z,(byte)2, z, z, z, z, z, z, z,(byte)40, z, z, z, (byte)1, (byte)130, z, z,z, (byte)2, (byte)2, (byte)2, z, z, z, z, z, z, z, z, z, z, z, z};
response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1));
response.sendError(response.SC_UNAUTHORIZED);
return;
}
else if (msg[8] == 3)
{
off = 30;

length = msg[off+17]*256 + msg[off+16];
offset = msg[off+19]*256 + msg[off+18];
String remoteHost = new String(msg, offset, length);

length = msg[off+1]*256 + msg[off];
offset = msg[off+3]*256 + msg[off+2];
String domain = new String(msg, offset, length);

length = msg[off+9]*256 + msg[off+8];
offset = msg[off+11]*256 + msg[off+10];
String username = new String(msg, offset, length);

out.println("Username:"+username+"<BR>");
out.println("RemoteHost:"+remoteHost+"<BR>");
out.println("Domain:"+domain+"<BR>");
}
}
%>