汇编网首页登录博客注册
startasm的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
好友圈

[2007-12-12 08:46] 汇编语言超浓缩教程(转)

也是一个汇编的教程,虽然没有王爽老师写的汇编语言好,但是也算不错了,支持下。

----------------
原文:
“ 哎哟,哥们儿,还捣鼓汇编呢?那东西没用,兄弟用VB"钓"一个API就够你忙活个十天半月的,还不一定搞出来。”此君之言倒也不虚,那吾等还有无必要研他一究呢?(废话,当然有啦!要不然你写这篇文章干嘛。)别急,别急,让我把这个中原委慢慢道来:一、所有电脑语言写出的程序运行时在内存中都以机器码方式存储,机器码可以被比较准确的翻译成汇编语言,这是因为汇编语言兼容性最好,故几乎所有跟踪、调试工具(包括WIN95/98下)都是以汇编示人的,如果阁下对CRACK颇感兴趣……;二、汇编直接与硬件打交道,如果你想搞通程序在执行时在电脑中的来龙去脉,也就是搞清电脑每个组成部分究竟在干什么、究竟怎么干?一个真正的硬件发烧友,不懂这些可不行。三、如今玩DOS的多是“高手”,如能像吾一样混入(我不是高手)“高手”内部,不仅可以从“高手”朋友那儿套些黑客级“机密”,还可以自诩“高手”尽情享受强烈的虚荣感--#$%& “醒醒!”  

  对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?―― Here we go!(阅读时看不懂不要紧,下文必有分解) 

  因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) 

  CPU是可以执行电脑所有算术╱逻辑运算与基本 I/O 控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086 有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器 CS,DS,SS 来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。 所以,程序和其数据组合起来的大小,限制在DS 所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。BP(Base Pointer):基址指针寄存器,可用作SS的一个相对基址位置;SI(Source Index):源变址寄存器可用来存放相对于DS段之源变址指针;DI(Destination Index):目的变址寄存器,可用来存放相对于 ES 段之目的变址指针。还有一个标志寄存器FR(Flag Register),有九个有意义的标志,将在下文用到时详细说明。 
  内存是电脑运作中的关键部分,也是电脑在工作中储存信息的地方。内存组织有许多可存放数值的储存位置,叫“地址”。8086地址总线有20位,所以CPU拥有达1M的寻址空间,这也是DOS的有效控制范围,而8086能做的运算仅限于处理16位数据,即只有0到64K,所以,必须用分段寻址才能控制整个内存地址。完整的20位地址可分成两部份:1.段基址(Segment):16位二进制数后面加上四个二进制0,即一个16进制0,变成20位二进制数,可设定1M中任何一个64K段,通常记做16位二进制数;2.偏移量(Offset):直接使用16位二进制数,指向段基址中的任何一个地址。如:2222(段基址):3333(偏移量),其实际的20位地址值为:25553。除了上述营养要充分吸收外,你还要知道什么是DOS、BIOS功能调用,简单的说,功能调用类似于WIN95 API,相当于子程序。汇编写程序已经够要命了,如果不用MS、IBM的子程序,这日子真是没法过了(关于功能调用详见《电脑爱好者》98年11期)。 

  编写汇编语言有两种主要的方法:1.使用MASM或TASM等编译器;2.使用除错程序DEBUG.COM。DEBUG其实并不能算是一个编译器,它的主要用途在于除错,即修正汇编程序中的错误。不过,也可以用来写短的汇编程序,尤其对初学者而言,DEBUG 更是最佳的入门工具。因为DEBUG操作容易:只要键入DEBUG回车,A回车即可进行汇编,过程简单,而使用编译器时,必须用到文本编辑器、编译器本身、LINK以及EXE2BIN等程序,其中每一个程序都必须用到一系列相当复杂的命令才能工作,而且用编译器处理源程序,必须加入许多与指令语句无关的指示性语句,以供编译器识别,使用 DEBUG 可以避免一开始就碰到许多难以理解的程序行。DEBUG 除了能够汇编程序之外,还可用来检查和修改内存位置、载入储存和执行程序、以及检查和修改寄存器,换句话说,DEBUG是为了让我们接触硬件而设计的。(8086常用指令用法将在每个汇编程序中讲解,限于篇幅,不可能将所有指令列出)。 

  DEBUG的的A命令可以汇编出简单的COM文件,所以DEBUG编写的程序一定要由地址 100h(COM文件要求)开始才合法。FOLLOW ME,SETP BY SETP(步步回车): 

  输入 A100 ; 从DS:100开始汇编 
  2.输入 MOV DL,1 ; 将数值 01h 装入 DL 寄存器 
  3.输入 MOV AH,2 ; 将数值 02h 装入 DL 寄存器 
  4.输入 INT 21 ; 调用DOS 21号中断2号功能,用来逐个显示装入DL的字符 
  5.输入 INT 20 ; 调用DOS 20号中断,终止程序,将控制权交回给 DEBUG 
  6.请按 Enter 键 
  7.现在已将汇编语言程序放入内存中了,输入 G(运行) 
  8.出现结果:输出一个符号。 
  ㄖ ←输出结果其实不是它,因WORD97无法显示原结果,故找一赝品将就着。 
  Program terminated normally 

  我们可以用U命令将十六进制的机器码反汇编(Unassemble)成汇编指令。你将发现每一行右边的汇编指令就是被汇编成相应的机器码,而8086实际上就是以机器码来执行程序。 
  1.输入 U100,106 
  1FED:0100 B201 MOV DL,01 
  1FED:0102 B402 MOV AH,02 
  1FED:0104 CD21 INT 21 
  1FED:0106 CD20 INT 20 
  DEBUG可以用R命令来查看、改变寄存器内容。CS:IP寄存器,保存了将执行指令地址。 
  1.输入R 
  AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
  DS=1FED ES=1FED SS=1FED CS=1FED IP=0100 NV UP EI PL NZ NA PO NC 
  1FED:0100 B201 MOV DL,01 

  当程序由DS:100开始执行,那么终止程序时,DEBUG会自动将IP内容重新设定为100。当你要将此程序做成一个独立的可执行文件,则可以用N命令对该程序命名。但一定要为COM文件,否则无法以DEBUG载入。 
  输入N SMILE.COM ;我们得告诉DEBUG程序长度:程序从100开始到106,故占用7 
  ;字节。我们利用BX存放长度值高位部分,而以CX存放低位部分。 
2.输入RBX ;查看 BX 寄存器的内容,本程序只有7个字节,故本步可省略 
  3.输入 RCX  ;查看 CX 寄存器的内容 
  4.输入 7  ;程序的字节数 
  5.输入 W ;用W命令将该程序写入(Write)磁盘中 

  修行至此,我们便可以真正接触8086汇编指令了。 当我们写汇编语言程序的时候,通常不会直接将机器码放入内存中,而是打入一串助记符号(Mnemonic Symbols),这些符号比十六进制机器码更容易记住,此之谓汇编指令。助记符号,告诉CPU应执行何种运算。 也就是说,助忆符号所构成的汇编语言是为人设计的,而机器语言是对PC设计的。  

  现在,我们再来剖析一个可以将所有ASCII码显示出来的程序。 
  1. 输入 DEBUG 
  2. 输入 A100 
  3.输入 MOV CX,0100 ;装入循环次数 
  MOV DL,00 ;装入第一个ASCII码,随后每次循环装入新码 
  MOV AH,02 
  INT 21 
  INC DL ;INC:递增指令,每次将数据寄存器 DL 内的数值加 1 
  LOOP 0105 ;LOOP:循环指令,每执行一次LOOP,CX值减1,并跳 
  ;到循环的起始地址105,直到CX为0,循环停止 
  INT 20 
  4.输入 G即可显示所有ASCII码 

  当我们想任意显示字符串,如:UNDERSTAND?,则可以使用DOS21H号中断9H号功能。输入下行程序,存盘并执行看看: 
  1.输入 A100 
   MOV DX,109 ;DS:DX = 字符串的起始地址 
   MOV AH,9 ;DOS的09h功能调用 
  INT 21 ;字符串输出 
  INT 20 
  DB UNDERSTAND?$;定义字符串 

  在汇编语言中,有两种不同的指令:1.正规指令:如 MOV 等,是属于CPU的指令,用来告诉CPU在程序执行时应做些什么,所以它会以运算码(OP-code)的方式存入内存中;2.伪指令:如DB等,是属于DEBUG等编译器的指令,用来告诉编译器在编译时应做些什么。DB(Define Byte)指令用来告诉DEBUG 将单引号内的所有ASCII 码放入内存中。使用 9H 功能的字符串必须以$结尾。用D命令可用来查看DB伪指令将那些内容放入内存。 
  6.输入 D100 
  1975:0100 BA 09 01 B4 09 CD 21 CD-20 75 6E 64 65 72 73 74 ......!. underst 
  1975:0110 61 6E 64 24 8B 46 F8 89-45 04 8B 46 34 00 64 19 and$.F..E..F4.d. 
  1975:0120 89 45 02 33 C0 5E 5F C9-C3 00 C8 04 00 00 57 56 .E.3.^_.......WV 
  1975:0130 6B F8 0E 81 C7 FE 53 8B-DF 8B C2 E8 32 FE 0B C0 k.....S.....2... 
  1975:0140 74 05 33 C0 99 EB 17 8B-45 0C E8 D4 97 8B F0 89 t.3.....E....... 
  1975:0150 56 FE 0B D0 74 EC 8B 45-08 03 C6 8B 56 FE 5E 5F V...t..E....V.^_ 
  1975:0160 C9 C3 C8 02 00 00 6B D8-0E 81 C3 FE 53 89 5E FE ......k.....S.^. 
  1975:0170 8B C2 E8 FB FD 0B C0 75-09 8B 5E FE 8B 47 0C E8 .......u..^..G.. 

  现在,我们来剖析另一个程序:由键盘输入任意字符串,然后显示出来。db 20指示DEBUG保留20h个未用的内存空间供缓冲区使用。 
  输入A100 
   MOV DX,0116 ;DS:DX = 缓冲区地址,由DB伪指令确定缓冲区地址 
  MOV AH,0A ;0Ah 号功能调用 
  INT 21 ;键盘输入缓冲区 
  MOV DL,0A ;由于功能Ah在每个字符串最后加一个归位码(0Dh由 Enter 
  MOV AH,02 ;产生),使光标自动回到输入行的最前端,为了使新输出的 
  INT 21 ;字符串不会盖掉原来输入的字符串,所以利用功能2h加一 
  ;个换行码(OAh),使得光标移到下一行的的最前端。 
  MOV DX,0118 ;装入字符串的起始位置 
  MOV AH,09 ;9h功能遇到$符号才会停止输出,故字符串最后必须加上 
  INT 21 ;$,否则9h功能会继续将内存中的无用数据胡乱显示出来 
  INT 20 
  DB 20 ;定义缓冲区 
  送你一句话:学汇编切忌心浮气燥。 
客套话就不讲了。工欲善其事,必先利其器。与其说DEBUG 是编译器,倒不如说它是“直译器”,DEBUG的A命令只可将一行汇编指令转成机器语言,且立刻执行。真正编译器(MASM)的运作是利用文本编辑器(EDIT等)将汇编指令建成一个独立且附加名为.ASM的文本文件,称源程序。它是MASM 程序的输入部分。MASM将输入的ASM文件,编译成.OBJ文件,称为目标程序。OBJ文件仅包含有关程序各部份要载入何处及如何与其他程序合并的信息,无法直接载入内存执行。链结程序LINK则可将OBJ文件转换成可载入内存执行(EXEcute)的EXE文件。还可以用EXE2BIN,将符合条件的EXE文件转成COM文件(COM 文件不但占用的内存最少,而且运行速度最快)。 
 下面我们用MASM写一个与用DEBUG写的第一个程序功能一样的程序。 
  用EDIT编辑一个SMILE.ASM的源程序文件。 
  源程序 DEBUG 程序 
  prognam segment 
  assume cs:prognam 
  org 100h A100 
  mov dl,1 mov dl,1 
  mov ah,2 mov ah,2 
  int 21h int 21 
  int 20h int 20 
  prognam ends 
  end 

  比较一下:1.因为MASM会将所有的数值假设为十进制,而DEBUG则只使用十六进制,所以在源程序中,我们必须在有关数字后加上代表进制的字母,如H代表十六进制,D代表十进制。若是以字母开头的十六进制数字,还必须在字母前加个0,以表示它是数,如0AH。2.源程序增加五行叙述:prognam segment 与 prognam ends 是成对的,用来告诉 MASM 及LINK,此程序将放在一个称为PROGNAM(PROGram NAMe)的程序段内,其中段名(PROGNAM)可以任取,但其位置必须固定。assume cs:prognam 必须在程序的开头,用来告诉编译器此程序所在段的位置放在CS寄存器中。end用来告诉MASM,程序到此结束, ORG 100H作用相当于DEBUG的A100,从偏移量100开始汇编。COM 文件的所有源程序都必须包含这五行,且必须依相同的次序及位置出现,这点东西记下就行,千篇一律。接着,我们用MASM编译SMILE.ASM。 
  输入 MASM SMILE ←不用打入附加名.ASM。 
  Microsoft (R) Macro Assembler Version 5.10 
  Copyright (C) Microsoft Corp 1981, 1988. All rights reserved. 
  Object filename [SMILE.OBJ]: ←是否改动输出OBJ文件名,如不改就ENTER 
  Source listing [NUL.LST]: ← 是否需要列表文件(LST),不需要就ENTER 
  Cross-reference [NUL.CRF]: ←是否需要对照文件(CRF),不需要则ENTER 
  50162 + 403867 Bytes symbol space free 
  0 Warning Errors ←警告错误,表示编译器对某些语句不理解,通常是输入错误。 
  0 Severe Errors ←严重错误,会造成程序无法执行,通常是语法结构错误。 

  如果没有一个错误存在,即可生成OBJ文件。OBJ中包含的是编译后的二进制结果,它还无法被 DOS载入内存中加以执行,必须加以链结(Linking)。以LINK将OBJ文件(SMILE.OBJ)链结成 EXE 文件(SMILE.EXE)时,。 
  1.输入 LINK SMILE ←不用附加名OBJ 
  Microsoft (R) Overlay Linker Version 3.64 
  Copyright (C) Microsoft Corp 1981, 1988. All rights reserved. 
  Run File [SMILE.EXE]: ← 是否改动输出EXE文件名,如不改就ENTER 
  List File [NUL.MAP]: ← 是否需要列表文件(MAP),不需要则ENTER 
  Libraries [.LIB]: ←是否需要库文件,要就键入文件名,不要则ENTER 
  LINK : warning L4021: no stack segment← 由于COM文件不使用堆栈段,所以错误信息 
  ←"no stack segment"并不影响程序正常执行 

  至此已经生成EXE文件,我们还须使用EXE2BIN 将EXE文件(SMILE.EXE),转换成COM文件(SMILE.COM)。输入EXE2BIN SMILE产生 BIN 文件(SMILE.BIN)。其实 BIN 文件与 COM 文件是完全相同的,但由于DOS只认COM、EXE及BAT文件,所以BIN文件无法被正确执行,改名或直接输入 EXE2BIN SMILE SMILE.COM即可。现在,磁盘上应该有 SMILE.COM 文件了,你只要在提示符号C:>下,直接输入文件名称 SMILE ,就可以执行这个程序了。 
...
...
评论次数(3)  |  浏览次数(2027)  |  类型(汇编相关) |  收藏此文  | 

[  fishboy   发表于  2007-12-12 10:52  ]

【我给博主添点东西,吼吼~~】 
Exe2bin
将可执行 (.exe) 文件转换成二进制格式。

要点

• Windows XP 和 Windows Server 2003 家族产品不使用该命令。只为了与现有的 MS-DOS 文件保持兼容性才包含此命令,但是因为其功能是自动实现的,所以在命令行使用时不起作用。 
 
• 此工具在基于 Itanium 的版本的 Windows 操作系统中不可用。 
 
• 此工具在基于 x64 的版本的 Windows 操作系统中不可用。 
 

语法
exe2bin [Drive1:][Path1]InputFile[[Drive2:][Path2]OutputFile]

参数
[Drive1:][Path1]InputFile

指定要转换的输入文件的位置和名称。InputFile 是必需的。

[Drive2:][Path2]OutputFile

指定要创建的输出文件的位置和名称。 

/?

在命令提示符下显示帮助。

注释
• Exe2bin 提供给软件开发商。它对一般用户是没用的。 
 
• 使用 exe2bin 命令时具有下列限制: 

• 输入文件必须是由链接程序生成的有效 .exe 格式,而且不能被打包。
 
• 文件驻留(或实际)的代码和数据部分一共必须小于 64 KB。
 
• 必须没有 stack 段。
 
 
• Exe2bin 根据用于 InputFile 和 OutputFile 参数的值执行如下特定操作: 

• InputFile 的默认文件扩展名是 .exe。Exe2bin 将 InputFile .exe 转换为 .bin 格式的文件(即程序的内存映像)并使用为 [Drive2:][Path2]OutputFile 指定的位置和文件名来存储输出文件。
 
• 如果不指定 Drive2 或 Path2,exe2bin 将把输出文件写到当前驱动器和目录中。
 
• 如果不为 OutputFile 指定文件名,exe2bin 就使用 InputFile 文件名。
 
• 为 OutputFile 指定的文件名的默认扩展名为 .bin。
 
 
• 可以转换为下列类型: 

• 如果没有在 .exe 文件中指定 CS:IP,exe2bin 将执行纯二进制的转换。如果该程序包含需要段重新定位的说明,exe2bin 会提示您输入修正值。该修正值是要将程序加载到的绝对段。只有将结果程序加载到程序指定的绝对内存地址时,才可以使用此结果程序。命令解释程序无法加载程序。
 
• 如果将 CS:IP 指定为 0000:100H,则文件将作为 .com 文件运行,并且汇编程序语句 ORG 将指令指针设置在 100H。将扩展名 .com 包括在 OutputFile 中。因为 .com 文件必须能够重新定位段,所以不允许进行任何段修正操作。即 .com 文件必须采取 Microsoft Macro Assembler 文档中说明的输入条件。然后,命令解释程序可以加载和运行程序,就像它加载和运行 Windows XP 磁盘上提供的 .com 程序一样。

[  Wednesday   发表于  2007-12-12 16:22  ]

我就不添什么了阿

收藏

[  li4096255   发表于  2008-04-28 09:44  ]

你太幸运了.
我"跟"你了.
不要都不行.

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码