分类目录归档:Sch00l days
Xilinx ISE使用不正常
前一段时间由于做毕设的原因要用到Xilinx的ISE软件,以前电子赛的时候也用过FPGA,但是用的是Altera的芯片,所以使用的设计系统为Quartus,现在由于导师要求使用Xilinx的芯片,所以设计系统也跟着换成了ISE,谁知刚装上软件就碰到了问题,工作区编辑窗口总不能正常显示,所有窗口都只能显示下边框的很窄一条,想要编辑VHDL文本只能将窗口设定成float模式才能正常看到窗口,这样很麻烦。
后来找了半天原因,居然是因为我的操作系统安装了桌面主题美化包,导致与ISE不兼容。后来换回XP的默认主题就好了。
希望这篇文章对大家有帮助。
三维曲线的画法
三维曲线的画法
三维空间曲线要用到plot3函数,这个和plot类似。plot3函数有三个参数,x,y和z轴,比如下面的例子:>> T = -2:0.01:2;
>> plot3(cos(2*pi*T),sin(2*pi*T),T)
如果安装了Symbolic Math Toolbox的话也可以用下面ezlpot3函数的方法:>> ezplot3('cos(2*pi*T)','sin(2*pi*T)','T',[-2 2])
三维曲面的画法
有mesh何surf两种命令来画三维曲面,它们使用的场合不同。前者是当z轴是x和y的显式函数时,后者是x,y,z中某个为其他2个的函数。
mesh函数
>> [X Y]=meshgrid(-2:.1:2, -2:.1:2);
>> Z = X.^2 - Y.^2;
>> mesh(X, Y, Z)
同理用Symbolic Math Toolbox可以直接执行>> ezmesh('X.^2 - Y.^2', [-2 2], [-2 2])
surf函数
在函数不能表示成z = f(x, y)时,需要用surf函数。比如x2+y2+z2=1.
先需要用柱面坐标或者球坐标来表示。这里用柱面坐标表示为 r2+z2=1x = sqrt(1-z2)cosθ, x = sqrt(1-z2)sinθ;
执行matlab指令:>> [theta, Z] = meshgrid((0:0.1:2)*pi, (-1:0.1:1));
>> X =sqrt(1 - Z.^2).*cos(theta);
>> Y =sqrt(1 - Z.^2).*sin(theta);
>> surf(X, Y, Z); axis square
同理用Symbolic Math Toolbox可以直接执行>> ezsurf('sqrt(1-s^2)*cos(t)','sqrt(1-s^2)*sin(t)', 's', [-1, 1, 0, 2*pi]); axis equa
壳里的日子(已完结)
大学三年级,我有幸参与了一个大学生创新计划项目《高强度软件防护》。当时是我们专业的指导教授roser老师找到我和同专业的几个学生,向我们介绍了这样一个计划对于我们来说是怎样一个机会。在信息对抗技术专业学习了两年多的时间,自己也发现在课程的安排上,的确更多的还是一些专业基础的内容,涉及到比较高层特别是软件方面的内容比较少。
而这一次这个项目我知道是学习信息安全技术的一个很好的机会,因此我当即就决定参与这样一个项目。我和班级内的5个人组成了一个创新小组,虽然对于软件加壳保护的内容我也没有实践过,但理论方面的内容以及软件破解的的一些调试过程我还是了解过相当一段时间的,为了能带领大家尽快进入状态,我担任了组长。
在计划开始之初和老师谈论有关计划的的时候,自信满满可以很好的体现我当时的状态,自己也不明白当时怎么会那么充满自信。小组内的成员水品参差不齐,有的MFC的程序都没怎么编过,有的连32汇编都没听说过。根据以上情况,对于整个创新计划的目的,我就明确了下来—-未必一定要设计出多么猛的软件,我可以多花一些时间等待其他组员的进度,也可以经常把我学到的东西教授给大家,但最重要的是每个人都能真正学到一些东西,多少并不重要。
创新计划开始后由于时至期末,大家都忙着考试,因此开始的阶段,计划一直处于停滞的状态,基本都是查阅一些资料而已。我一直希望能在网上找到一些例子,最好是高级语言编写的,毕竟汇编代码看起来总让人比较乏味,但这样的例子着实不多。
到了寒假,我分配给大家的任务主要还是分模块查资料,有的antidump,有的antidebug,以及反拷贝等内容,进一步了解壳的概念。因为加壳保护这个概念说起来似乎很容易,但稍微深想一下,壳代码究竟怎么样才能附加到被保护的程序上,就会让人比较疑惑了。我接触过软件破解一段时间,但真正写壳可完全是另一码事,头一次感到有点蒙。以前买过看雪的一本《加密与解密》,一直没有仔细翻阅过,这次回到家,我开始从PE文件结构看起,不过复杂的结构体看了前边忘后面,真的是有点烦,索性就跳过这部分继续跳跃性前进,中国革命的道路不也是这么走出来的吗。别说是软件保护,就是32位汇编,PE文件结构学校都没有讲过一点。软件安全,网络安全技术,或者说是安全类技术,相信很多在校学生都有感触,老师能教给你的很有限,多半是基础的过时的东西。真正要学都是靠自学的,哪个黑客是学校教出来的啊~~
经过一段时间的研究,我大致明白了软件壳保护的机制。对于常规的可执行文件(PE文件),系统都会以一个相当复杂但规整说明性极强的方式组织并存贮在硬盘上。当然运行的时候硬盘上的PE文件也会以几乎相同的格式加载到内存当中。而代码或数据以及资源这些2进制信息都会以区段的形式存放,总的来说一个PE文件包括有头部说明部分,包括文件类型说明,文件格式大小的信息,入口点信息(程序第一句要执行的代码位置),区段的偏移位置,输入函数表等,再来就是代码,可能是一段,也可能几段,然后是数据,以及资源(图片,声音,按钮,图标等都是资源)。这些内容以前也有所涉及,只是从来没有比较系统完整的全貌。而软件加壳保护,说简单了就是修改程序入口点到你写的壳代码部分(当然要添加到该PE文件空闲的部分),然后在壳代码执行完毕后再jmp回真正的入口点。这样做可以使得调试器,反汇编器等逆向分析程序的过程变得复杂。当然各种反调试代码也可以加入到壳代码中,或加入相应的定制的功能(时间限制,注册验证等内容)。对于PE文件也可以进行变换,将原来的一些说明信息,标志位等修改,在壳内再复原,这样就不能简单的跳过壳的部分了。一旦说起来,这就是一堆的生疏概念,越是向下研究,生疏的就越多。
于是我决定,先从《加密与解密》中的这个已给出的的例子开始,完整的再现一下,借此了解一下整个流程。看雪的书中给出了的例子主要是一个压缩壳,也就是对于被处理的PE文件进行信息压缩,去掉一些冗余,以比较简单的形式记录有关信息,再对各个区段进行编码实现数据体积减小。许多开源的壳的压缩都采用了APLIB这个压缩引擎,这次看雪的例子也不例外。首先是对原始文件的各项属性的记录,特别是输入表的部分,系统给出的输入表的结构虽然规整,但对于必要的信息表达并不需要如此,因此我可以自己构造一个输入表的形式来存储这些信息。对于资源中的图标,在压缩的时候要跳过,这样被处理的文件才会有图表,否则就是一个蓝边的白框,难看极了。将压缩的数据添加到壳内,然后修改壳的一些属性信息,入口点,资源大小等。壳其实还是用32位会编写的,编译也用的MASM32 来进行,但VC这个环境里提供了兼容并包的方式来组织一个工程。你完全可以在shell.asm上添加上编译环境的信息,然后以统一的VC工程形式编译整个工程。这样编译完的Shell.asm就成了一段机器码,在VC下就当他是bytes数据好了,然后修改不同位置的信息就达到了修改对应变量的目的,再将这些bytes数据添加到新生成的PE文件中就好了。新的PE文件在运行时,会运行壳代码,进行解压缩,并一步步还原原始数据,添加相关表,说明符,标志位,各区段等到内存的正确位置,然后就开始运行原来的程序代码了,壳的任务就此完成了。
MFC用起来还是很方便的,因此我将看雪原来win32的代码添加到我的MFC写的程序中,刚开始的部分,读PE文件等这样的内容,我都是每一句仔细分析研读,然后才写入我的程序中。越往后发现这样太好时间和精力了,而且也不是能简单的理解那些操作了,索性就开始从一句一句的粘贴到了一个一个函数的粘贴。这样的工作很快就接近了尾声,编译运行,选一个PE文件进行处理,然后就是运行看结果了。这与以往的程序不同,在中间的编辑过程中几乎不能停下来看看阶段性成果,只有完全编好后才能开结果,而这样的话一点出现问题就很难调试找问题了,因为之前未验证的代码量实在太庞大了。而且壳代码也无法用VC环境来调试,因此代码都是在被处理PE文件中,只能借助OLLDBG这样的第三方调试器来进行。幸运的是,这个程序编译通过后,运行完全正确。寒假也几乎结束了,经过这么一次壳的实验过程,我也大致了解了一个壳的运作编写流程了。
回到学校,和其他组员交流了一下,很遗憾其他人都没有什么进展,资料搞了一些但零零散散毫无组织,这样的资料的价值等于零。毫无组织的信息,为了能解读必须要话比资料本身理解更长的时间来分类归档,因此这些资料我至今都压在垃圾箱里。虽然很遗憾,但也多少在我的预料之中,而且我也并不感觉到太失望。毕竟,他们的基础并不怎么样。为了能让大家开始学起来,我决定让他们先编写一些小程序,熟悉一下MFC,就编一个简单文件读取的窗口程序吧。从这个为期一周的例子里,我就看到了每个人对一个程序的理解程度,借此我也强调了编程规范性的问题,特别是合作编程时接口的设定问题。并不是骄傲,也不是自负,但程序编写我真的是进行过太多了,大大小小的程序,从C到C++,MASM,C#.Net,javascript,VB等我都编过不少。所以我相信我的建议特别是这些基本的建议,应该都是比较正确的。
这是当时第一次会议的记录:
“小组开会时间:2月21日8点到9点
参加人员:WYS LSG HT WGX roser(导师)
会议内容:
这是本学期第一次小组讨论有关软件防护项目的内容,首先大家对假期资料查找学习后各自的收获进行了总结。发现的问题是,最初的分组工作十分不切合实际,将这个项目按反调试反跟踪,反dump 等空荡荡的词语进行分工,让每个人并不能很有效的了解要做的工作。
我在假期中,尝试根据书中的一个例子进行一个壳例程的编写(基本就是复制别人的代码),感受一下一个壳的大概步骤,希望能对接下来的工作起一个方向导引的作用,但相应的资料查得并不多。
WYS假期里查找了有关反跟踪的资料,虽然打印了出来,但他自己说,这资料虽然看了两次,但好像还是没有看得太懂,这当中涉及到的许多知识因为都没怎么接触过因此,效果并不明显。
LSG查了有关加密的内容,但其个人认为资料上所说大部分为概念性的内容,比如密码学上的一些思想。因此他并没有实际动手进行相关的软件上的编写测试。
HT查了反dump方面的资料,由于它之前的相关基础较好,因此对于所查资料,概括得比较明晰,同样他也在假期看了我的那本《加密与解密第三版》中的例程,并发表了相应的看法。
朱伯宇还没返校
由于一个壳的编写工作比较复杂,想分得很开比较困难,因此我们打算在编写的过程中不断进行工作的分配。
昨晚讨论的结果是,由于大部分工作环境在win32vc6.0下进行,加上大家之前也接触过一点mfc的例子的,为了让大家熟悉一下环境。第一项任务是每个人编写一个mfc下的窗口,选择文件后读取相应路径,显示文件内容的小程序。目的只有一个,熟悉工作环境,了解相应变量添加,函数调用规则等。为接下来的编写热身。
接下来的计划大致如下,由于pe文件的结构分析是一个加壳软件通常必要的过程,因此打算合力编写一个pe分析软件,借此让大家熟悉pe文件结构,在Vc下完成,但合力来写得话,我的想法是每个人首先拿到相同的一个窗口原程序,在此基础上添加比如5个窗口类函数,调用每一个函数就可以在信息栏显示一个部分的pe文件分析结果..”
于是接下大家开始编写这个读取文件的窗口了,即使是这么简单的程序,还是暴露出了甚多问题。
第二次会议记录如下:
“时间:2月28日晚上
人员:ZBY,LSG,WYS,WGX
HT有事没能参与讨论
本次讨论了之前的 mfc程序的编写,大家在显示文件内容的文本框的编写时遇到了多行显示的问题。但经过相应属性的调整,解决了该问题。同时,在对比各个人编写的程序时,也发现了大家对变量命名比较随便。因此接下来的程序编写,在程序中各个成员变量及全局变量都要采用更严格的命名规则,例如成员变量m_strpathname要能看出变量所处的域。
对比了大家的软件,最终决定采用ZBY的对话框进一步完成下面的工作。同时要制定接下来pe文件头的编写时用到的全局变量。ZBY负责将WGX和他的程序进行对比,完善之前的工作。
LSG接下来完成dos头的读,ZBY完成nt_header中imagefileheader的读,WYS完成nt_header中imageoptionalheader32的读,HT来查接下要工作要进行的部分,下一次讨论他来主持。我对各个变量进行制定,同时进行输入表的函数读取进行研究。”
革命都是以一个催化剂式事件为导火索的开始的,我们的项目在进行了这一个阶段后,似乎也有些停滞了,大家的兴趣似乎也并不高涨。我本人来说,兴趣也稍微有些下降,主要是要研究的内容实在很头疼,壳注入文件的方式我一直不能灵活掌握,这意味着我脱离不了现成的例子,独自开发。缓慢的前进步伐让我也有些反感,这从来都不是我希望发生在自己身上的。
挑战杯的到来正好充当了这一角色,为了能拿我们的项目参加挑战杯,我们决定夜以继日开始赶进度,很多基础性的核心工作都是在这一阶段完成的。大家的热情也调动起来了,周末时我们会去信息楼6002一天都在里面集体编程,这景象煞是有震慑力。后来为了不影响教室里的其他人,我们就去了创新计划同时批到的一个专属实验室。
说起这个实验室还真是有不少故事,计划开始不久,就得到了这样一个远在戊区的小实验室,20平米左右吧,初来乍到,脏乱差来形容一点不夸张。我们花了一天时间来打扫整个屋子,当时干的热火朝天的,好像从高中毕业以来就没搞过比较大型的扫除工作。回想以前的高中生活或是初中生活,搞大扫除都是比较愉快的回忆,通常这都代表一部分人可以出去自由活动,当然劳动本身做好了也会让自己心旷神怡于整洁的环境~~几个让我至今仍有很深回忆的同学我都能马上想到他们打扫卫生的样子哈~~有点跑题了。除了打扫工作,添置桌椅也是不知实验室的一部分,从远远地4号楼搬大号桌椅过来可一点也不轻松,当时我们租了两辆板车,我一直是坐在司机的位置,其他人在后面推,感觉好极了。就这样折腾了3,4回终于将一件能待人的屋子搞出来了。
通常临近周末的晚上,我们组都会在这个实验室搞到一两点钟才回宿舍。经过一番筛选,我选择了Bambam作为我们软件架构的底层支持,也就是说,我们的软件是以Bambam为核心编制的,在上面扩展相应的功能,这样可以大大缩短工程开发时间。Bambam是我在网上找到的一个用高级语言(C++)写成的壳,这样的例子真的不多,这个壳是BedRock根据BigBoot的一篇文章写成的,但由于时间比较紧迫,我也并没有话很多时间来读相应的代码(如果读懂的话应该会很有价值)。但Bambam本身是一款压缩壳,并不能很好的完成我们的anti工作,虽然他的壳本身还真是用高级语言写生成的dll加载,似乎更有优越性,但当时看来反而更不易懂了。为此我结合看雪的例子,还是采用了32位汇编来写shell部分的代码,然后混合编译。为了能搭建这一平台还真是花了不少功夫,可以说整个软件最关键的部分就是这里了。这里稍微回忆一下当时的过程,我们的操作要在Bambam处理之前进行,也就是相当于Bambam压缩了一个我们加了一层壳的软件。对于原始的Pe文件,首先由ZBY添加一个区段然后传给我一新区段的地址,并把原始入口点改为新区段的地址,然后把原始的入口点存好也传给我,这一部分的接口算是整个程序设计的最合理的一部分了。
我的工作就是要在新区段里写入壳代码,这部分我花了很长的时间才想明白究竟怎样做到,一个Shell.asm究竟如何变成机器码存入到这个区段中,我又是如何实现的修改这个asm中的变量的,本来想起来很明白的事,到了真正编程的时候却怎么也想不通该怎么让编译器完成我的要求。这个关卡我花了很久的时间才逐渐思考明白,直到今天我还记着刚刚想通时我向身边人讲解的那一幕,Incredible~~
编译器编译C代码很好理解,将它汇编成obj文件,里面就是机器码,反汇编就对应于汇编代码。当然连接后就成了带有很多说明信息的.exe可执行文件。而32汇编代码呢,汇编写好后,32位汇编器只要做很少的工作将一些宏展开,做一些处理就变成了机器码,可以送入连接器了。但两者结合起来会怎么样呢,如何用C来修改汇编代码中的变量,你可能会说申请为全局变量就好了,的确~~那如何像读取字符串一样将汇编代码读到内存再写入新的区段呢,从例子看来,似乎汇编代码就像是一个数据数组被改来改去,然后被写入到新的区段中。经过我一段时间的思考和不断地尝试(这方面的介绍太少了,特别是这些技巧性实际操作),发现了如下的事实:我们知道汇编写代码的时候可以定义一些标识符,用来做jmp,但对于真正的机器码级别来说,这些标识符就是一些地址(比如0x00400210)。在Vc环境下C代码和汇编代码同时编译(当然汇编代码的编译setting里要设置上masm32.exe的位置,和编译的参数)。但与此同时,我可以在汇编代码中设置一些标志位,而C访问这些标志位可以直接访问到汇编代码的类逻辑地址(比如0x00400210),因此我就可以在汇编代码的开始和结束设置上标志位,然后像读取字符串一样将机器码读出来。当然一旦读出了这些字符我们就可以任意修改了,不要说是某个变量,就是代码也没问题,然后再将这些内容写入到壳所在的区段里,就完成了壳代码的添加。
以上提到的过程,说起来好像就是上面短短的十几行,但我真正想到确实花了不少的时间。过了这样一个卡,我完成了壳代码添加基础,当然很多细节还没有完全处理掉。Api函数地址的添加,可移植性,以及所有的anti,当然一切都有了基础了。底层的接口或者说平台我已经搭建好了,接下来只要添加代码就好了,不再需要考虑这个代码和添加之间的关系了。
壳代码的添加就是一个漫长的过程了,当时为了赶着参加挑战杯,大家相继添加了一些代码,我当时主要利用findwindow,实现了对ollydbg的ANTI-DEBUG,也就是查找到这个窗口后,就关闭它。这里涉及到的一个关键问题,就是API函数的调用。在此之前写过的一些VC程序,用到的函数都是由MFC封装的,并没有直接看到API的使用,当然这个概念我一直是有的,API是操作系统提供给用户使用的一些函数。因为Windows并不想让你知道或者说没必要让你知道它底层的工作方式,因此提供了这样一些接口函数帮助你实现有关的功能。API也就是application interface,应用程序接口。这些函数被保存在系统的动态链接库中,比如MessageBoxA这个函数就位于user32.dll中,系统执行这个api的方式分成两种,一种是静态挂接,另一种是动态加载。汇成一句就是,系统加载动态链接库到内存,在从中找到user32.dll中的MessageBoxA后,将参数通过堆栈传过去。总体来说我看的资料还是比较少,有时实在懒得汪洋大海里四处搜寻就索性通过自己的不断实验摸索解决这些问题,api的调用就是根据一些小例子不断摸索出来的。虽然其实没什么深奥的,但没做过就是觉得有难度。
列举了几种常见的ollydbg版本的窗口名称和类名作为查找的对象,保证了大部分版本的Ollydbg都能被检测到,其实就是到刚刚我还有添加了两种新的类名作为查找的的对象。Findwindow可以对窗口名和类名进行查找,一旦找到,说明该程序在运行,就可以给该窗口发WM_DESTROY消息让他中止。另外一种反调试就是用另一个现成的API函数IsDebuggerPresent()来检测调试器的存在,虽然这个方法也比较容易对付,ollydbg对其有天生的免疫,但出于完整性考虑还是实现了这样一个功能。
为了使壳程序功能扩展更为方便,我为壳定制了一个大概的结构,开始部分为api函数动态加载,也就是加载所需要的动态链接库,然后从动态链接库中找到所需要的函数的地址存入定义好的数据单元等待以后调用。壳末尾部分,主要用于各类数据的存放,包括库函数的名称,api函数的名称等,而功能部分则主要在这两者之间进行扩展。这样一个壳的模型就搭建好了,扩展功能的话,尽量用api实现,因此查找有用的api就十分必要了。另外api名称的确定也很关键,很多资料文献并没有按照api的原始名称给出,比如MessageBoxA这函数很多文献上就写成MessageBox,但实际上并不存在这样一个函数。这里借助一个api函数查询助手的小软件实现对各类api名称的准确查询。
挑战杯展示期间,我们的作品就大致是这样一个状态了,可以压缩,内部还有我们自己写的壳,功能上有一个简单的反调试,和反拷贝功能,以及一个简单的注册认证功能。每一个功能都十分简陋。但总算是一个完整的程序了,挑战杯的校内预选赛算是相当的扯了,说是有专家来查看,等了一天也没见个人影,后来听说是来过个人但根本就不是搞这方面的人,哪看得懂啊,妄我用了那么多时间耗在那该死的挑战杯报告上,真是浪费感情,荒唐至极啊。
不过总算因为这次准备,开发的进度进展了不少,核心的一些问题解决了不少。接下来有空的时间我就不断扩充壳的功能了,首先是反调试方法的扩充,除了将IsDebuggerPresent改写为三句等效汇编代码,再来就是调用一些其他的调试器检测函数进行检测,以及int3陷阱的she检测法。扩展了这些功能的过程中,时不时也出现了一些小问题,比如编写时,VC注入代码时,我发现计算的汇编代码的偏移量并不正确,只能是重新编译几次,又调整了几次汇编代码的位置才好。到现在也还是不太清楚,什么原因导致的这样的偏移量计算错误。在调试的时候,用watch方式观察变量里的偏移明明是正确的,但一赋值就变了。现在每次改写,只能祈祷不出现问题才好,十分怀疑是VC环境的BUG。
后来其他人又添加了反DUMP的代码,为了区分这些模块,使得程序加壳时可以有选择加载这些模块,我就对每个程序模块进行了标号区别,这样在VC将壳代码写入的时候,就根据界面选择的结果有选择的添加代码,没有被选中的,为了偏移量计算的正确就将代码用NOP填充。功能逐渐完善了,剩下的工作就是修修补补了。但由于每一次修补之间都拖沓了很长时间,因此常常提笔忘字,得花一些时间来回想一些工作方法。
后来,注册算法这部分确实改了不少。思考了一下最开始提出反拷贝的概念,感觉一开始理解的还是有偏差,并不是说要固定的将一个程序放在某一台电脑上,而不让它运行于其他的电脑上,而是说注册码不通用,对于一台电脑上注册通过后,并不能保证其他的电脑也能用此注册码工作。这就需要在注册时考虑注册名,注册码和机器码,三者保证注册软件的唯一性。机器码的提取常见的有硬盘序列号和网卡MAC以及CPU序列号等,但由于一开始没有找到有效地提取机器码的方式,我就是用SYSTEMINFO的摘要作为机器码,从一定程度上说,这也保证了一定程度上杜绝了不同两台机器共用一套注册码。
注册码的输入当然是用dosstub实现了,这也是我们的加壳软件的一大创新点,虽然应用上看似多次一举,但至少提出了一个新思路,算是抛砖引玉吧。也就是说注册码的输入利用了PE程序里开始的一段16位的dos代码实现,因此对于不知情的人很难找到这段代码,也就无从了解注册点的位置进行突破。而注册的验证,除了对三者的的运算,特别的在比较阶段,没有对比的过程,而是将运算结果与入口点进行运算,这样既保证了入口点的加密处理,又保证了注册的验证。也就是说注册不正确,程序就运行不正常,但究竟怎么样运行才正常是无法推算出来的,保证了注册算法的不可逆行。这主要是依据了一个常数来处理这个入口点,而这个常数只有注册码设计者才知道。用户名确定后,注册码的目的就是让机器码和用户名以及注册码经过运算达到这一常数0x14c09002,当然应用中,这个常数是可以改变的,应对不同的产品也可以定制不同的常数。
这样大部分的工作就几乎完成了,虽然说起来只有短短的几个自然段,但实际经历的时间大概有5个月吧,中间也是断断续续。后来无意中想到的不能让程序每次注册失败就导致程序运行失败,这样总还是不太美观,因此又结合了SEH异常处理方法,增加了一个线程级别的异常处理函数,主要应对与注册失败导致程序返回到错误的内存地址后,不至于弹出一个错误对话框,而是弹出我预定的一个MessageBox注册失败提示。
做到这里,已经是这个学期了,刚好赶上操作系统的课程的学习,用到了不少多线程编程。正好考虑到了壳内反调试这一环节的弊端,反调试只在程序运行开始阶段存在,一旦被绕过,就会导致后期反调试无效,而且绕过也并不难,只要运行程序后在附加调试器就成功绕过了。为此,要为反调试单独设立一个线程来保证被保护程序整个生命周期的安全。说的很繁琐,其实就是用createthread函数将反调试部分作为一个线程函数来执行,保证程序执行期间抑制保持反调试状态。想不到一开始提到的多线程反调试技术就这样简单的实现了,也不知道自己理解的对不对,但效果还是起到了。好像很多技术,我都是仅仅听过一个名字,也没有查什么资料就按照自己的理解开始做了,估计细节上很难保证和官方的想法一样。经过整个软件的编写,我发现更多的时候我倾向于自己的实验测试而不是网上大段的资料,也不知道是对还是错。
后期对程序的改进,功能上的确多了不少,但都不是特别有难度,在程序代码结构上我又做过几次调整,力求大段的汇编代码不至于看起来晦涩难懂。也易于扩展各部分的代码。整个加壳程序的编写,目前算是一个告一段落的时刻了,这期间有关于代码的生成,编译过程,PE文件结构,线程,API,动态库这些系统级别的封装好的概念,我理解了很多,对于今后从事软件安全的话有很大的帮助,也为我编写各类程序开拓了视野,提供了思路。遇到问题也多了很多解决方案。That’s all
破解FlashExtractor.exe
说到破解软件,恐怕我从4,5年前就开始接触了,那个时代还是trw,softice等盛行的时代。记得当时简单的爆破了一款破解LINUX登录密码的软件(LC4),不过就是用OD跳来跳去找到了一个关键跳转然后再用反汇编软件找到该位置进行了语句的更改就完成了破解,当时还想把那文章发表到网友世界上晒晒(当时经常看的杂志)。现在看来当时还真是有些幼稚弱啊~~连汇编语言都不懂的情况下竟然也蒙到了这关键的跳转。
经过了这么长的时间虽然也在逐渐了解这方面内容,但也一直是含蓄点冰,未能深入了解。在大学3年纪借着做一个软件加壳项目的机会,有了一个突飞猛进的学习机会。这里顺带总结一下鄙人的学习旅程好了。这个项目主要是做一个壳,以前还没怎么脱过壳,现在居然要写壳了,多少有些措手不及。于是我从最基本的PE文件结构开始了解,写了个简单的PE文件格式读取程序,接下来为了能尽快进入shell部分的编写,加上对32位汇编并不是很熟悉(课程里仅学习过16位的)。因此我用BamBam这个VC++写成的壳来加以修改。很快我了解到了壳代码仅仅是作为字串形式写入被加壳的文件以及如何在VC环境下完成代码的汇编以及代码的注入。这样剩下的工作就很简单了,创建一个新的区段供我的壳代码使用,添加各种ANTI功能的汇编代码到shell.asm中就可以了。当然入口点要开到我的区段位置。外层是原来BAMBAM的压缩壳。api的调用机理,内部构造,与动态链接库的关系,以及很多系统的知识也都是在这个过程中了解到的。这方面的内容以后我会单独写一篇文章来介绍,这里就当做是预告吧。想到什么就写了什么,估计文字看来会有些混乱~~
好了,闲话说了不少正式开始破文。该软件主要是用来提取Flash里的图片音频资源,当年我编写的一个坦克大战游戏用到的声音就是从一个Flash游戏里提取出来的。可惜这个软件只能使用10次。虽然也不怎么常用,但今天刚好有空就拿起来进行了一下调试。软件注册后提示重新运行软件来检测注册码,这样的话,注册码多半是存在了注册表中,下一次运行软件时会读取该注册码和用户名来运算验证。我以前也尝试过类似方式的软件的破解(比如winavi,估计转视频的都用过,虽然网上公布有他的注册码),但由于其算法很复杂实在跟不下去了,就放弃了。
找到注册码验证的位置就比较关键了,可以再regopen类似的api上下断点,不过我并没有这样。首先我用regmon进行注册表监视,excluded无关的操作,再运行一次注册过程。然后将regmon的记录进行include。接下来就用olldbg来加载该软件吧,并没有壳。方便了很多,也没有加入各种Anti,用delphi编写的(peid的结果)。载入后,显然是软件开始的引导部分包含了大概10个call吧,以前调过MFC的程序好像也是类似的结构,这样的过我就F8过每一个call同时观察REGMON的结果,直到我发现过某个CALL时,REGMON有反应,重新载入程序,然后F7该call就行了,当然进去以后还是很多call,用类似的方法逐层深入。最终到达一个界面下,可以看到OLLDBG有相关ASCII提示,看到注册表项,估计到了注册表的读取了。等到注册表读取完毕后,下面的call可以F7进去看看,发现了一些比较短小的CALL估计是字符串求长度,移动等操作用的也没细分析。接下来到了某一个CALL中了,发现有明显的循环处理。估计到了注册码的验证了。程序首先用“wanghouli”这个字符串对用户名一位一位异或操作(仅对低四位),高四位不变。跳出后,又进入一个函数和注册码4位4位进行比较,判断是否相同,当然其中涉及到很多长度的考虑,很复杂,越分析越复杂。
最后看了大概的验证过程,就选
wanghouli 作为用户名 p````p`` 作为注册码
直接运行就通过了,当时那叫一个激动啊,第一次分成功整出了一个注册码。虽然crackme玩过一些,但真正对一个实用的软件进行注册码级别的破解还真是头一次,这里记录一下。
电子设计大赛总结
比赛对于我来说很早就已经结束了,前后累加将近3,4个月的训练,我确实收获了不少,相关的体会我已经在阶段性的报告中进行了陈述,这里仅对比赛前后的点点滴滴进行一下小结,算是对我难得的一次经历的历史性回顾吧。
9月2日,正式的比赛拉开了帷幕。清晨我们学校的各个队伍就集结在了会议室,才7:20而已,平日这个时间还在梦乡中徘徊呢。相关的领导进进出出,直到巡视员的姗姗到来,我们正式进入了比赛场地。题目已经发布在网站上了,电源,宽带运放,无线通信…这些我们训练提及过的内容似乎都如约而至,只不过题目乍看起来还有一些欺骗性,”它们都是伪装成几何问题的函数问题”(《嫌疑犯X献身》)。比赛前我们小组一直在研究的数字滤波内容,目标自然就锁定在与之相关的‘数字均衡’题目上了。
整个系统的结构确定还是不难的,题目上也给出了相当的约束条件。我的初期任务主要是研究后级的功率放大模块,也就是从FPGA输出的信号将之功率放大。题目上要求效率较高,这首先使我们想到的就是采用D类功放,比赛开始前,我们就已经投入了经历在其中,因此选择它更是理所当然(想当然的结果就是Surprise!)。由于IR2105类驱动芯片一直尝试不通,而我本人也一直怀疑这个芯片使用的必要性(主要是对D类功放两个MOS管的控制原理理解不透)。好在时间看起来还是比较充分的。运放的搭建,带阻网络的搭建都有现成的电路,一个小时就能搞定,做FPGA滤波环节的人其实训练中期就曾经设计了思路比较新颖效果也还不错的多带通FIR滤波系统。因此我就秉持的比较放松的心态开始具体研究MOS管组成D类功放的原理。最开始的尝试是用单一的MOS管组成简单的放大电路,将PWM波放大后级加上简单的RC滤波就还原出了想要的正弦波形,但对于桥式的MOS管的控制,虽然仿真出来尚且有波形,但实际结果却差强人意。
大概用了近两天的时间,我终于明白了D类功放中桥式电路的控制原理,以及驱动器的使用必要性了。原因说出来就比较清晰了,两个相连对接的MOS管要想控制保证一个导通,一个闭合这样的状态不断转换,就必须要有两个独立的控制信号分别加载在他们GS端。
举例来说,如果我有两个信号源,产生两路方波分别加载到他们的GS上,就能独立的控制他们的开关了。但实际情况是,这两路方波一定是相位差为零,仅仅是逻辑相反而以,这样的信号源就做不到了(如何能让两个信号源分同步呢)。如果采用其他手段,比如让FPGA产生这样的逻辑相反的同步PWM波去分别控制两路GS,乍看起来好像也可以。但事实,由于两路PWM一定是共地的,这就使得桥的中点,也就是上方的MOS管的S级永远是地,因此当然输出的信号都是毛毛了。
因此驱动器的作用就产生了,他能产生两路不共地的PWM波。其实其内部在低频时就相当于光耦合,或变压线圈的作用。但意识到这个问题花了不少的时间,好在另一个研究IR2105的同学已经有了突破,终于搞明白了这个芯片的外围电路参数的确定办法。接下来我们就用这个放大电路进行了烧烤实验,功率确实够大的,8欧姆的负载加上时间不长就有烤肉味产生。但好在是成功放大了功率。这会儿我又花了点时间完成了前级放大电路的搭建,要说的NE5532效果确实很棒,一个简单的负反馈,不用太多的调节,出来就是完美的正弦波。时间到了接近第三天的晚上,本来我们很早就对系统的整体完成了设计。但发现功率在15V供电的情况下很难达到预期指标,不过通过占空比的调节终于让直流功率吧总功率顶上去了,与此同时我也完成了全系统的联调入箱的操作。可惜后期突然听说输出功率不包括直流功率,我当时无论如何也不能接受这个想法,但也没办法,人疲倦的时候就是经不住新思想,而这也使我们作出导致了几乎满盘皆输的决定—将半桥电路供电改为双电源,这意味着整个电路板上共地的许多点要打开改为-15V的点。这一改动过后,我们打开了电源,残酷的事实发生了,由于改动不全面,一处短路导致IR2105烧毁,正赶上12点多的时间,要芯片却没有老师,还好前一组留了块备用的,我们当时那叫一个感激啊。调整好后,我们做了类似西方人的饭前祷告,闭上眼的几秒钟差点没睡着~~再次上电终于将有了点波形,虽然没有了直流分量,全部是交流功率,但事实是交流功率小的可怜。还好我们都比较冷静,要不然恐怕就要跳楼了。原因恐怕很难找到,很可能是刚刚对于电路板的改动使得电路中各节点的焊接可能效果不理想等等,实在是不愿意多想了。面临的解决方案恐怕只能是改回去了,我是有点扛不住了,还好另一个还比较能扛,开始了交流返回直流的孤单征程。大概第四天早晨7点钟就完成了改造工作,输出是有了,效果比之前的差了很多,是啊,电路改来改去,效果不差才怪呢。原来好好的正弦波现在搞得跟三角波似的。
啥也别说了,时间不允许我们有更多的抱怨,赶紧装箱吧。
测试时间相比结束时又过了两天的时间,总体归纳整个测试环节,我们太缺少经验了。
这一次测试也彻底断送了我们整个比赛的延续,有客观原因,当然更要总结的还是主观原因。 测试前我们还是蛮有自信的,毕竟整个系统半调子的也算是做出来了。到了专家面开始了最后的准备,我们前面一组正好是北邮一组,做的题目和我们一样。我仔细的观察了他们的电路,以及整个测试过程。我想先说说他们的测试吧,因为印象还真是挺好的。从他们的整个系统看来,显然系统似乎比我们的复杂一些,电阻电容差不多比我们多了一倍,板子也多了几块。有一点确实很让我有感触,他们电路板之间的连线都是可插接的,输入输出线也都是可以选择性的插接的。最关键的是后级的功放用MOS管上面都有厚厚的散热片,负载电阻虽然和我们用的一样都是带有散热壳的大电流承载的电阻,但电路上,这个电阻却是悬空的,下面用两个散热片将之顶起,这样可以更大限度的降低电阻的温度。我们那个电阻工作起来起码140度啊,周边的电线皮都焦了,以上这两点细节我真是从来都没考虑过。测试时也很从容,让测哪一部分就接上哪一部分,保证效果一直良好。但他们的功放似乎仅仅采用了乙类推挽式放大,优点就是波形非常好,当然效率肯定最后没有达到指标。不过整体感觉测试的很轻松,把他们的电路都展现出来了。
轮到我们组了,这会儿我可没那么有自信了,就冲最后那个波形,我们那个和他们那个比起来,真是差很多(谁叫人家没用D类功放呢,牺牲了效率,换来了波形)。等老专家开始测试我们组,首先让我上电,让我接上它的信号源,然后他才根据那个毫伏表来调节信号源电压。就这点我就十分BS这个专家了,更BS他们的设备。信号源哪能不调好电压就接入我们的放大电路呢,电压太大烧了我的放大器怎么办呢。一个信号源连个显示输出电压的功能都没有,居然还用毫伏表测,还用个模拟的示波器,我滴神啊。当然我说的也未必全对,知识训练过程中,我一直使用数字示波器,而且信号源也使用示波器来测输出,那毫伏表在我看来无论如何都是老土的代表。
问题来了,接入我们的电路后,这老头说什么也不能把信号源调到有效值5mV,非说是我电路自激了。还好后来竞赛组组长前来解围,纠正了这个老专家,从原理上告诉了他信号源和毫伏表以及放大器输出电阻的关系,真不知道这专家究竟是学什么的。总算是解决的输入问题,接下来问题又来了,测量我的放大倍数,说不够,我就调了一下控制倍数的滑动变阻器,他又来事了,说我调电路参数。我跟他理论了半天,说我这个系统设计之初就设置了可以调节的功能,增加适应性,这老专家那叫一个不情愿啊(无知真可怕)。接下来带阻网络又来事了,说我们的改了它们给的电路参数,我解释说原图没办法达到-10db的衰减指标,我仅仅是将一个电阻改成了可调节的滑动变阻器,确保可衰减-10db。他连衰减网络频谱曲线测都没测就记了个‘滑动变阻器’,天知道他这么写的意思。接下来的均衡后的输入,我无论如何也想不到他居然吧扫频仪的输入接到了运放的输入端,那意味着400倍的放大倍数去放大扫频仪输出地100mv的电压,根本就是一个方波输出啊,哪有拿方波测量网络特性的(这点也是后来我才意识到,当时只是觉得怪怪的,我们都是直接让扫频仪接带阻输入的)。当然了,一个方波的输入和我们之前的设定的均衡系统肯定不匹配啊,均衡效果当然很糟,但还好我们的均衡采用的多带通技术是可以调节的,可是那老头又开始发牢骚了,说我们又要调电路参数,怎么跟他解释我们的数字滤波系统的优越可调适应性都不行。最后当然是滤波等于X了。
后级功放就更完,整个测试过程中,我最担心的就是这个,这老头巨磨叽,脱了老长时间,还不让断电,后级电阻都快成人造小太阳了。等到它测试功放输出,果然波形也跟人造小太阳一样四相散射。波形不好,他居然直接就说其他指标都不测了,当时我也却是理亏,谁叫咱波形不好呢,想想就只能灰溜溜的走人了。
以上的愤慨致辞如违反国家有关法律,请即刻销毁。因销毁不及时所产生的任何法律(包括宪法,加法、减法、乘法、除法、剑法、拳法、脚法、指法、民法,刑法,书法,公检法,基本法,劳动法,婚姻法,输入法,没办法,国际法,今日说法,吸星大法,与台湾关系法及文中涉及或可能涉及以及未涉及之法,各地治安管理条例)纠纷或责任本人概不负责。本人谢绝任何跨省、跨市,跨县、跨乡、跨村的追捕行为。确因不抓不足以平民愤,或不抓就领不到薪水养家户口的公职人员,建议携带工作证、身份(韩度)证、结婚证/离婚证、独生子女证、健康证、暂住证、毕业证、边防证、县以上government机关出具的介绍信温情操作。废话完了,以上声明内容部分来自网络修改而成,感谢广大网友的无私奉献精神。
客观地讲,我们的确存在准备上的不足。后级电路应该采用可插接方式连接,检查前级时,断开后级防止温度过高,同样也应该增加足够的散热装置。我们设计系统的想法看来和专家的想法有一定的偏差,谁知道出题人究竟是如何思考的呢。我们把重点放在了数字部分,要想进行数字部分的频谱可调,可不是每个组都能做到的啊,可惜我们根本没机会展示这个功能,同样未能展示的还包括了一个10带通滤波和DDS。带阻网络我们本来还很自豪居然调成了题目要求的-10db,可居然反而被专家认为不合格,他只看元件不看频谱曲线就已经奠定了这一点。最后的波形本来是可以很好的,知识改了来那个两次电路后,波形变差了,导致后级彻底废掉,这里经验就是要坚持自己的想法,哪怕有一点偏差,总比正确的却什么也没做出来好,盲目改变只能是一团糟。另外选题时一定要选人少的,而不是最熟的,因为你熟别人也熟,物以稀为贵啊。
比赛虽然没有获得很好的成绩,但对最终的结果我还是很欣然的接受了,从一开始也不是为了一个奖而参加的比赛。培训的过程中学到的东西真的是一生受用,现在随时想到一个电子系统,似乎自己马上就可以着手开始,到哪里买器件,哪里找资料,怎么制作,要注意的细节似乎都是理所当然。这期间我做过的那个万能遥控器,也真的是为生活增加了不少乐趣。当然最应该感谢的人一定是4个月来无私的培训我的老师们,没能获奖也许对他们的伤害更大哈~ 2009,我经历的不平凡的一年。
VC程序如何释放文件
很久以前写过一个在EXE的资源中释放出一个文件,然后加载运行做些事情的小程序,时间久了,忽然又有这个需求的时候,居然忘记是如何做的了,原来的程序代码早被删了,自己胡乱试验几次,结果弄出N个蓝屏出来,只好上网查了一下,但没有发现很理想的资料。只好吭哧吭哧费了九牛二虎才搞定,所以在此记录一下,以免以后忘记了。
需要:释放一个名为001.jpg文件到C盘根目录,并修改成名字002.jpg
在VC工程的的Resource View画面中,鼠标右键->add->add resource,出现添加资源画面->选”Import…”->找到001.jpg->确定,显示资源类型定义对话框,在资源类型定义中,自己定义一个不存在的类型名,这里叫TROJANHORSE,然后就把001.jpg添加进来了。这个时候,”Resource View”画面中会多出一个”TROJANHORSE”类型,下面资源名为:IDR_TROJANHORSE1,这个名字可以自由修改。
在代码中,写一个函数,(借助了网上资料,出处忘记了)
BOOL ReleaseMyFile(LPCTSTR lpszDestFilePath, LPCTSTR lpName, LPCTSTR lpType) { HRSRC hRsrc = ::FindResource(NULL, lpName, lpType); if (NULL == hRsrc) return FALSE; HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc); if (NULL == hGlobal) return FALSE; DWORD dwSize = ::SizeofResource(NULL, hRsrc); LPVOID pBuffer = ::LockResource(hGlobal); BOOL bRt = FALSE; FILE* fp = _tfopen(lpszDestFilePath, _T("wb")); if (fp != NULL) { if (dwSize == fwrite(pBuffer, sizeof(char), dwSize, fp)) bRt = TRUE; fclose(fp); } return bRt; }
然后就可以在main中调这个函数释放资源文件了,具体代码如下:
BOOL bRt = ReleaseMyFile(TEXT("c:\002.jpg"), MAKEINTRESOURCE(IDR_TROJANHORSE1), TEXT("TROJANHORSE"));
当然,可以把001.jpg换成exe或者sys文件,做该做的事情。
关于键盘驱动
关于键盘驱动
今天想在DOS下用C语言写一个带菜单的程序,一开始没有一点思路,主要是不知道怎样实现菜单的功能,于是上网搜索,得到启发:可以通过读取键盘的扫描码,从而实现菜单的功能。于是我开始研究怎样去获取键盘的输入信息,经过大半天的Google,现在我将关于键盘的知识记录下来。
我用的机器的平台是Intel Atom N270+945GSE+ICH-7M+EMC5035。
所谓的键盘控制器(KBC),也就是Intel 8042;它位于EC中,8042负责读取键盘扫描码并将其存在缓冲器中供程序读取;另外还有一个芯片ECE1077,它负责连接键盘和EC,将键盘动作转换成扫描码。CPU通过两个IO端口与8042通信,这两个IO端口就是0x60,0x64端口。下面介绍一下CPU怎样通过这两个IO端口与8042通信。
8042有四个8位的寄存器,它们是输入寄存器(RO)、输出寄存器(WO)、状态寄存器(RO)和命令寄存器(R/W)。
读输出寄存器:inportb(0x60);
写输入寄存器:outportb(0x60,data);
读状态寄存器:inportb(0x64);
读命令寄存器:先向0x64端口写命令0x20:outportb(0x64,0x20);再从0x60端口读数据:inportb(0x60);
写命令寄存器:先向0x64端口写命令0x60:outportb(0x64,0x60);再向0x69端口写数据:outportb(0x60,data);
状态寄存器和命令寄存器的每一位都是有特定意义的,如下:
状态寄存器:
Bit7: PARITY-EVEN(P_E): 从键盘获得的数据奇偶校验错误
Bit6: RCV-TMOUT(R_T): 接收超时,置1
Bit5: TRANS_TMOUT(T_T): 发送超时,置1
Bit4: KYBD_INH(K_I): 为1,键盘没有被禁止。为0,键盘被禁止。
Bit3: CMD_DATA(C_D): 为1,输入缓冲器中的内容为命令,为0,输入缓冲器中的内容为数据。
Bit2: SYS_FLAG(S_F): 系统标志,加电启动置0,自检通过后置1
Bit1: INPUT_BUF_FULL(I_B_F): 输入缓冲器满置1,i8042 取走后置0
Bit0: OUT_BUF_FULL(O_B_F): 输出缓冲器满置1,CPU读取后置0
命令寄存器:
Bit7: 保留,应该为0
Bit6: 将第二套扫描码翻译为第一套
Bit5: 置1,禁止鼠标
Bit4: 置1,禁止键盘
Bit3: 置1,忽略状态寄存器中的 Bit4
Bit2: 设置状态寄存器中的 Bit2
Bit1: 置1,enable 鼠标中断
Bit0: 置1,enable 键盘中断
有了以上知识,再对照键盘的ScanCode表,我们就可以编写程序读取并判断键盘输入的数据,并根据不同的按键执行不同的动作。
另外,发给8042的命令除了以上所讲的读/写命令寄存器以外,还有其他一些命令;这些命令可以分为两类:
一类是直接发给8042的命令,包括设置键盘密码,自检,开启和禁用键盘等;
还有一类是先发给8042,再通过8042间接发送给8048的命令。这里的8048类似上述的ECE1077,它将键盘动作转换成ScanCode供8042读取。这类操作命令有设置键盘LED灯,设置扫描码类型,设置键盘工作方式等。
这两类命令的详细信息如下:
① 通过写端口0x64,直接发送给8042的命令:
20h
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
60h
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
A4h
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
A5h
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
A6h
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
AAh
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
ADh
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
AEh
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
C0h
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。
D0h
准备读取Output Port。结果被放在Output Register中,随后通过60h端口读取出来。
D1h
准备写Output Port。随后通过60h端口写入的字节,会被放置在Output Port中。
D2h
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
②通过写端口0x60,间接给8048发送命令:
EDh
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
0xED命令后面跟的命令数据格式
EEh
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
F0h
选择Scan code set。Keyboard系统共可能有3个Scan code set。当Keyboard收到此命令后,将回复一个ACK(FAh),然后等待一个来自于60h端口的Scan code set代码。系统必须在此命令之后发送给Keyboard一个Scan code set代码(01~03)。当Keyboard收到此代码后,将再次回复一个ACK,然后将Scan code set设置为收到的Scan code set代码所要求的。如果数据为0x00,则主机返回当前使用的键盘扫描码集的编号。
F2h
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK(FAh),然后,将2字节的Keyboard ID一个一个回复回去。
F3h
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK(FAh)。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
F4h
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK(FAh)。然后继续接受Keyboard的击键。
F5h
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK(FAh),接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
F6h
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
FEh
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
FFh
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK(FAh),然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
③从0x60读出的数据:
00h/FFh
当击键或释放键时检测到错误时,则在Output Bufer后放入此字节,如果Output Buffer已满,则会将Output Buffer的最后一个字节替代为此字节。使用Scan code set 1时使用00h,Scan code 2和Scan Code 3使用FFh。
AAh
BAT完成代码。如果键盘检测成功,则会将此字节发送到8042 Output Register中。
EEh
Echo响应。Keyboard使用EEh响应从60h发来的Echo请求。
F0h
在Scan code set 2和Scan code set 3中,被用作Break Code的前缀。
FAh
ACK。当Keyboard任何时候收到一个来自于60h端口的合法命令或合法数据之后,都回复一个FAh。
FCh
BAT失败代码。如果键盘检测失败,则会将此字节发送到8042 Output Register中。
FEh
Resend。当Keyboard任何时候收到一个来自于60h端口的非法命令或非法数据之后,或者数据的奇偶交验错误,都回复一个FEh,要求系统重新发送相关命令或数据。
83ABh
当键盘收到一个来自于60h的F2h命令之后,会依次回复83h,ABh。83AB是键盘的ID。
Scan code
除了上述那些特殊字节以外,剩下的都是Scan code。
关于ScanCode:
当键盘上有键被按下,松开,按住,键盘将产生扫描码( Scan Code ),这些扫描码将被 i8048 直接得到。扫描码有两种,Make Code 和 Break Code。当一个键被按下或按住时产生的是 Make Code ,当一个键被松开产生的是 Break Code。每个键被分配了唯一的 Make Code 和 Break Code ,这样主机通过扫描码就可以知道是哪一个键。简单的说就是按下键,产生一个 Make Code。松开键,产生一个 Break Code。
到目前为止一共有三套扫描码集( Scan Code Set ),ps/2 键盘默认使用第二套。不过可以设置 i8042,让 i8042 把得到的 Scan Code 翻译成 Scan Code Set 1 中的 Scan Code ,这样键盘驱动从 i8042 得到的所有 Scan Code 都是第一套中的 Scan Code(实际中驱动也是这么做的)。所以我们只讨论 Scan Code Set 1 。需要说明的是 Scan Code 和 ASCII码完全不相同。
在 Scan Code Set 1 中,大多数键的 Make Code,Break Code 都是一个字节。他们的 Make Code 的最高位都为0,也就是他们的 Make Code 都小于 0x7F。而他们的 Break Code 为其 Make Code 或运算 80h ,也就是把 Make Code 的低7位不变,最高位设置为1。
还有一些扩展按键,他们的 Scan Code 是双字节的。他们的第一个字节都是E0h,表明这是一个扩展键。第2个字节,和单字节 Scan Code 的情况相同。
还有一个特殊的键,Pause/Break 键,它的 Make Code 为 E1,1D,45 E1,9D,C5,注意是 E1h 开头。而且它没有 Break Code 。
Brother louie(经典的舞曲)
这是80年代的经典舞曲,Modern Talking的brother louie。
这首歌实在是太有名了,以至于被50多种语言翻唱,
原唱Modern Talking 是两人的德国dance-pop二人组合,在80年代中后期红遍世界
后来乐队解散,90年代后期重新组合,出了新的专辑,可惜已经远没有当年的悦耳了。
下面是歌词
Deep love is a burning fire stay,
cause then the flames grow higher Babe,
don ‘t let him steal your heart
It’s easy,easy
Girl,this game can’t last forever
Why, we cannot live together?
Try, don’t let him take your love from me
You’re no good, can’t you see
Brother louie, Louie, Louie
I’m in love – set you free
Oh, she’s only looking to me
Only love breaks her heart
Brother Louie, Louie, Louie
Only love’s paradise
Oh, she’s only looking to me
Brother Louie, Louie, Louie
Oh, she’s only looking to me
Oh, let it Louie
She is undercover
Brother Louie, Louie, Louie
Oh, doint what he’s doing
So, leave it Louie
‘Cause I’m her lover
Stay,’cause this boy wants to gamble
Stay, love is more than he can handle
Girl, oh, come on, stay by me forever, ever
Why does he go on pretending
That his love is never ending
Babe, don’t let him steal your love from me
下载地址:http://www.crossbayblvd.com/files/The_Stories_-_Brother_Louie.mp3
MV中的背景为《美国往事》,也是很经典的讲人生的电影。属于黑帮史诗型的~~