【转贴】80386ASM程序设计基础(八)

网络流量异常信息分析方法研究 本课题针对网络安全中网络流量异常的分析方法进行研究,提出一种基于机器学习和深度学习的异常检测算法。该算法采用卷积神经网络(CNN)和长短时记忆神经网络(LSTM)结合的方式,通过训练得到二分类模型,从而实现对网络流量异常的检测。随着互联网的飞速发展,网络攻击事件日益增多,网络安全问题成为了亟待解决的问题之一。常见的网络攻击手段包括 DDoS 攻击、SQL 注入、XSS 攻击等,这些攻击手段可能导致网络系统发生异常,给网络运维、数据安全带来极大的挑战。 阅读详情
80386实模式下编程
 80386在实模式下是一个更快的8086,它不但可以进行32位操作,而且还可以进32位寻址,并且还可以使用80386的扩展指令。不过,由于是在实模下,寻址的最大空间为1M。在一个段内,段的最大长度不超过64K,否则就会发生异常。
 在8086下定义一个段的完整格式是:
 段名 [定位类型]  [组合类型]  [‘类别’]
 80386下定义一个段的完整格式是:
 段名 [定位类型]  [组合类型]  [‘类别’] [属性类型]
 说明:属性类型有两种:USE32和USE16,USE32表示32位段,USE16表示16位段。如果你在程序中用到伪指令.386,那么默认的属性类型就是USE32(32位段),如果没有用伪指令指定CPU的类型,那么默认的属性类型就是USE16,在实方式下只能使用16位段,即用USE16。
 eg:
    CSEG PARA PUBLIC USE32;定义一个32位的段
      AA DW ?

      BB DD ?
      CC DB ?
      DD DW ?
      EE DW 0,0,0.....
    CSEG ENDS
 由于在80386中用到了66H操作前缀和67H地址前缀,因此尽管在实式模式下,只要设定的CPU类型是80386,仍然可以进行32位操作,可以进行32位寻址,66H,67H这两个前缀无需程序员在程序中书写,汇编程序会自动加上的。只要在程序中对32位操作数进行访问,或进行32位寻址,那么就会加上操作数前缀66H和地址前缀67H。相反,如果在32位段中对16位或8位的访问,汇编程序中也会加上这两个前缀。
    下面将给出一个例子程序,演示一下在80386的实模式下编程的方法与技巧(这是从网上down的一个程序,不是我写的,但我会作详细的解剖,并与8086下的程序设计作出比较):
    用十进制,十六进制,二进制三种形式显示双字存储单元F000:1234中的内容
   |------------------MAIN PROC------------|
   | .386                                  |
   | code segment para public 'code' use16 |
   |   assume cs:code                      |
   | begin:                                |
   |   mov ax,0f000h                       |
   |   mov fs,ax                           |
   |   mov eax,fs:[1234H]                  |
   |   call todec                          |
   |   call newline                        |
   |   call tohex                          |
   |   mov al,'H'                          |
   |   call echo                           |
   |   call newline                        |
   |   call tobin                          |
   |   mov al,'B'                          |
   |   call echo                           |
   |   call newline                        |
   |   mov ah,4ch                          |
   |   int 21h                             |
   |---------------------------------------|  
    ;sub-function todec
    todec proc near
       pushad
       mov ebx,10
       xor cx,cx
     dec1:
       xor edx,edx
       div ebx
       push dx
       inc cx
       or eax,eax
       jnz dec1
     dec2:
       pop ax
       call toasc
       call echo
       loop dec2
       popad
       ret
   todec endp
  
   ;sub-function tobin
   tobin proc near
      push eax
      push ecx
      push edx
      bsr edx,eax
      jnz bin1
      xor dx,dx
    bin1:
      mov cl,31
      sub cl,dl
      shl eax,cl
      mov cx,dx
      inc cx
      mov edx,eax
    bin2:
      rol edx,1
      mov al,'0'
      adc al,0
      call echo
      loop bin2
      pop  edx
      pop  ecx
      pop  eax
      ret
   tobin endp

   ;sub-function tohex
   tohex proc near
     countb=8
     enter countb,0
     movzx ebp,bp
     mov   ecx,countb
     mov   edx,eax
   hex1:
     mov al,dl
     and al,0fh
     mov [ebp-countb+ecx-1],al
     ror edx,4
     loop hex1
     mov cx,countb
     xor ebx,ebx
   hex2:
     cmp byte ptr [ebp-countb+ebx],0
     jnz hex3
     inc ebx
     loop hex2
     dec ebx
     mov cx,1
  hex3:
     mov al,[ebp-countb+ebx]
     inc ebx
     call toasc
     call echo
     loop hex3
     leave
     ret
  tohex endp
 
 ;sub-function toasc
 toasc proc near
     and al,0fh
     cmp al,'0'
     cmp al,'9'
     seta dl
     movzx dx,dl
     imul dx,7
     add al,dl
 toasc1:ret
 toasc endp

 ;sub-function newline
  newline proc near
    push dx
    push ax
    mov dl,0dh
    mov ah,2
    int 21
    mov dl,0ah
    int 21
    pop ax
    pop dx
    ret
  newline endp

  echo proc near
    push ax
    push dx
    mov dl,al
    mov ah,2
    int 21h
    pop dx
    pop ax
  echo endp   
 剖析:
   先来看主程序框架,下面就是MAIN PROC:
   |------------------MAIN PROC-------------------------------|
   |.386;定义处理器的类型为386表示可以使用所有80386指令       |
   | code segment para public 'code' use16                    |
   |   assume cs:code                                         |
   | begin:                                                   |
   |   mov ax,0f000h                                          |
   |   mov fs,ax;将f000h装入段寄存器fs                        |
   |   mov eax,fs:[1234H];将1234H内存单元中的双字送给寄存器EAX|
   |   call todec;调用子过程todec                             |
   |   call newline;调用子过程newline进行回车换行             |
   |   mov eax,fs:[1234h];                                    |
   |   call tohex;调用子过程tohex                             |
   |   mov al,'H'                                             |
   |   call echo;显示字符H                                    |
   |   call newline;                                          |
   |   mov eax,fs:[1234H]                                     |
   |   call tobin;调用子过程tobin                             |
   |   mov al,'B'                                             |
   |   call echo                                               

  
   |   call newline                                           |
   |   mov ah,4ch                                             |
   |   int 21h                                                |
   |----------------------------------------------------------|
   主程序中的内容一目了然,很简单。和8086下唯一不同的是就是要用伪指令定义CPU的类型,并且段寄存器的定义多了一个属性类型USE16,再就是32位操作,使用80386的指令,其它的和8086下没有什么区别。
   重点是要分析几个过程,从网上down下来时,过程newline和toasc没有实现代码,因为这很简单,所以上述toasc,newline,echo的过程体是由我写进去的,这两个过程体代码不多而且非常简单,就不作介绍了。重点介绍todec,tobin,tohex。
   a.子过程todec,这个子过程的主要功能是将f000:1234双字单元的内容用十进制显示,下面就来看每一行代码:   
   |-----------------------------------------------------------|
   |todec proc near                                            |
   |   pushad                                                  |
   |   mov ebx,10                                              |
   |   xor cx,cx                                               |
   |  dec1:                                                    |
   |   xor edx,edx                                             |
   |   div ebx                                                 |
   |   push dx                                                 |
   |   inc cx                                                  |
   |   or eax,eax                                              |
   |   jnz dec1                                                |
   |  dec2:                                                    |
   |   pop ax                                                  |
   |   call toasc                                              |
   |   call echo                                               |
   |   loop dec2                                               |
   |   popad                                                   |
   |   ret                                                     |
   |todec endp                                                 |
   |-----------------------------------------------------------|
   分析:将一个数用十进制数来表示,要它对它进行除以10的运算,得到商和余数。再将商除以10,如此循环直到商为0为止,在这个过程中得到的一系列的模(余数)就是十进制数系列。在主程序中,已经将f000:1234双字单元的内容放到EAX寄存器中,由于后来要用十六进制数,二进制数显示,所以EAX寄存器的内容不允许改变,因此在子过程的一开始,要将EAX的内容先入栈,所以子过程的一开始就用PUSHAD将8个32位通用寄存器的内容全部入栈。在标号dec1不断地进行除以10运算,将所得到的余数全部入栈,同时用cx进行计数。在标号dec2中,逐个弹出在标号dec1中得到的余数,然后分别将它们显示出来,这样就可以将该存储单元中的内容用十进数表示,下面解释每一条指令的功能:
   a1.pushad;将8个32位通用寄存器全部入栈
   a2.xor cx,cx;cx清0
   a3.mov ebx,10;10=>ebx
   a4.xor edx,edx;edx清0
   a5.div ebx;edx存放高32位,不过是0,EAX中存放低32位,即ffff:[1234]双字的内容;除法得到的商放在EAX,余数放在EDX 
   a6.push dx;将edx的低16位dx入栈
   a7.inc cx;cx+1=>cx
   a8.or eax,eax;对eax进行或操作,主要是用来判断eax是否为0,即判断商是否为0,从而判断是否应该结束标号为dec1的循环。
   a9.jnz dec1
   a10.pop ax;将放在堆栈中的余数逐个弹出到ax中
   a11.call toasc;显示ax的内容
   a12.call echo
   a13.loop dec2;将所有的余数显示完毕
   a14.popad;8个32位通用寄存器全部出栈
   a15.ret

   b.子过程tohex
    PUSH BP
    SP=>BP
    SP<=SP-CNT1
   |------------------------------------------------------------|
   |tohex proc near                                             |
   |  countb=8                                                  |
   |  enter countb,0                                            |
   |  movzx ebp,bp                                              |
   |  mov   ecx,countb                                          |
   |  mov   edx,eax                                             |
   |hex1:                                                       |
   |  mov al,dl                                                 |
   |  and al,0fh                                                |
   |  mov [ebp-countb+ecx-1],al                                 |
   |  ror edx,4                                                 |
   |  loop hex1                                                 |
   |  mov cx,countb                                             |
   |  xor ebx,ebx                                               |
   |hex2:                                                       |
   |  cmp byte ptr [ebp-countb+ebx],0                           |
   |  jnz hex3                                                  |
   |  inc ebx                                                   |
   |  loop hex2                                                 |
   |  dec ebx                                                   |
   |  mov cx,1                                                  |
   |hex3:                                                       |
   |  mov al,[ebp-countb+ebx]                                   |
   |  inc ebx                                                   |
   |  call toasc                                                |
   |  call echo                                                 |
   |  loop hex3                                                 |
   |  leave                                                     |
   |  ret                                                       |
   |tohex endp                                                  |
   |------------------------------------------------------------|  
   分析:该子过程的功能是将f000:1234双字单元的内容以16进制数显示出来,首先来考虑一下将一个数以16进制数表示出来的算法,事实上在汇编语言中操作数一直都是以十六进制表示的。因此,在这个子过程中不可以像上一个子过程一样,通过不断的除法取模得到结果。事实上,我们只需要将32位操作,以每半个字节(四位)的内容显示出来就可以了,有了这一编程思想,就很容易看懂上面的子过程。当然你们会问,为什么要每次只显示半个字节而不显示一个字节呢?呵呵,十六进制的十六个数是从0000-1111,不就是半个字节了。所以要循环8次才可以显示出32位的EAX,所以这里用ror指令来不断循环移位,每次右移4位放到dl的低4位中。这8个半字节分别放在[ebp-1]至[ebp-8]的存储单元中。不过,存储的顺序是由低位到高位,如果就这样显示结果肯定显示反了。标号hex2,hex3的主要功能是用来判断f000:1234双字单元的内容是否为0,如果为0,只需要将最后结果显示一个0即可,否则就显示出8位内容。下面是每条指令的功能:
   b1.countb=8;伪指令定义一局部变量countb,其值为8
   b2.enter countb,0;建立堆栈框架指令
   b3.movzx ebp,bp;对bp进行零扩展
   b4.mov   ecx,countb;8=>ecx
   b5.mov   edx,eax;将eax=>edx
   b6.mov al,dl
   b7.and al,0fh;取低4位
   b8.mov [ebp-countb+ecx-1],al;将8个半字节的内容逐一送到[ebp-1]至[ebp-8]的内存单元中
   b9.ror edx,4;对edx进行循环右移,每次移动4位
   b10.loop hex1
   b11.mov cx,countb
   b12.xor ebx,ebx;ebx清0
   b13.cmp byte ptr [ebp-countb+ebx],0;下面的语句主要用来判断源操作数f000:1234的内容是否为0,如果是0,就在屏幕上只显示一个0
   b14.jnz hex3
   b15.inc ebx
   b16.loop hex2
   b17.dec ebx
   b18.mov cx,1
   b19.mov al,[ebp-countb+ebx];逐一显示[ebp-8]到[ebp-1]的内容。
   b20.inc ebx
   b21.call toasc
   b22.call echo
   b23.loop hex3
   b24.leave;释放堆栈框架
   b25.ret
    
   c.子过程tobin
   |---------------------------------------|
   |tobin proc near                        |
   |   push eax                            |
   |   push ecx                            |
   |   push edx                            |
   |   bsr edx,eax                         |
   |   jnz bin1                            |
   |   xor dx,dx                           |
   |bin1:                                  |
   |   mov cl,31                           |
   |   sub cl,dl                           |
   |   shl eax,cl                          |

   |   mov cx,dx                           |
   |   inc cx                                                   
   |   mov edx,eax                         |
   |bin2:                                                       

   |   rol edx,1                                                
   |   mov al,'0'                                               
   |   adc al,0                                                 
   |   call echo                                                
   |   loop bin2                                                
   |   pop  edx                            |
   |   pop  ecx                                                 
   |   pop  eax                                                 
   |   ret                                                      
   |tobin endp                                                  
   |---------------------------------------|
   分析:将一个数用二进制数显示出来,只需要用ROL指令就可以了。这里作者写的程序就是这个思路,在标号bin1中主要判断f000:1234单元的内容是否为0,如果为0,那么只需要在屏幕上显示一个0就可以了。否则的话,就用ROL指令对源操作数移位32位,从最高位31位到最低位逐一显示出来,程序设计思路很简单,没有什么复杂的算法,下面看每一条指令的含义:
   c1.push eax;eax入栈
   c2.push ecx;ecx入栈
   c3.push edx;edx入栈
   c4.bsr edx,eax;对eax进行扫描,并把第一个为1的位号送给edx
   c5.jnz bin1;如果eax不为0,就跳到c7去执行
   c6.xor dx,dx;如果eax为0,就将dx清0
   c7.mov cl,31;从c7到c12主要用来设置计数器cx,如果eax=0,那么就设置cx=1,如果eax不等于0,那么就设置ecx=32
   c8.sub cl,dl
   c9.shl eax,cl
   c10.mov cx,dx
   c11.inc cx
   c12.mov edx,eax
   c13.rol edx,1;从c13到c15主要用来显示二进制数据,顺序是从最高位31位到最低位0位
   c14.mov al,'0'
   c15.adc al,0
   c16.call echo
   c17.loop bin2
   c18.pop  edx;edx出栈
   c19.pop  ecx;ecx出栈
   c20.pop  eax;eax出栈
   c21.ret
   在后续的篇幅里将主要介绍保护式下的段页管理机制及及如何在保护模下编程。

SAP PS 收入确认方法配置清单(成本推导收入 / 项目进度推导收入) 摘要:本文详细介绍了SAPPS模块中两种收入确认方法的配置流程:成本推导收入(成本比例法)和项目进度推导收入(里程碑法)。通过事务码OKG1-OKG5等关键配置步骤,分别实现基于累计成本比例和里程碑完成权重的收入确认逻辑。文章对比了两种方法的适用场景和管控要点:成本法适用于成本与进度强相关的项目,需严控预计总成本;进度法则依赖明确的里程碑验收。同时提供了落地建议,包括项目类型绑定、数据校验和变更管控等最佳实践,为SAPPS系统收入确认功能实施提供完整指导。 阅读详情

相关推荐

80386汇编语言详解与使用

主要讲了80386汇编语言的知识和基本使用,我个人人为有它结合练习就够了

80386ASM程序设计基础()

 80386实模式下编程 80386在实模式下是一个更快的8086,它不但可以进行32位操作,而且还可以进32位寻址,并且还可以使用80386的扩展指令。不过,由于是在实模下,寻址的最大空间为1M。在一个段内,段的最大长度不超过64K,否则就会发生异常。 在8086下定义一个段的完整格式是: 段名 [定位类型]  [组合类型]  [‘类别’] 80386下定义一个段的完整格式是: 段名 [定位类型

kingcaiyao的专栏 1798

proxmoxVE 离线包

内网环境,没有互联网。离线安装pve的时候,许多在线更新包没法安装。下面提供pve7.0的离线包,包括debain,ceph

8086汇编语言讲座

关于8086汇编语言,是与计算机原理相结合的,通过汇编语言可以加深对计算机原理的掌握和理解。另外汇编语言还是可以干成事的,比如破解,外挂等都会用到它。

80386ASM程序设计基础

    80386ASM程序设计基础     kingcaiyao        80386 ASM程序设计基础,呵呵,这是最近一段时间我的业余爱好。本期将连续推出若干篇有关80386ASM程序设计基础,主要介绍80386ASM指令的详细用法及如何在80386实模式下,保护模式下及虚拟8086模式编程以及我会详细介绍80386下的段页管理机制,我会将80386下的指令与8086下的相同指令进行比

Hi, CT here! 2864

DEMO 源码系列_旋转星云

; File Name   : F:/256B/3D/AWAK-3D.COM.386.model tinyCode segment byte public CODE use16assume cs:Code, ds:Codeorg 100hpublic startstart proc nearpush 0A000hpop esmov ax, 13hint 10h  ; - VID

dididu1515的专栏 869

DEMO 源码系列_海底世界

; File Name   : F:/256B/3D/NJUFNJUF.COM.386.model tinyseg000 segment byte public CODE use16assume cs:seg000, ds:seg000org 100hpublic startstart proc nearmov ax, 13hint 10h  ; - VIDEO - SET VID

dididu1515的专栏 1089

我们都曾是菜鸟

菜鸟就是新手,每个人不管干什么都是从菜鸟做成高手的,别管别人怎么说,认真干好每一件事,你离高手就不远了。

青春不老,奋斗不止! 5933

菜鸟成长路

起飞!!!

lmjf_8的专栏 7508

python3菜鸟教程官网,python菜鸟教程100例

大家好,本文将围绕python3菜鸟教程官网展开说明,python菜鸟教程100例是一个很多人都想弄明白的事情,想搞清楚python菜鸟教程下载需要先了解以下几个事情。10个免费学习 Python 的中文网站 如果你想要学习 Python,那么这篇文章将会介绍 10 个免费的中文网站。

zjl102562的博客 2325

基于菜鸟教程的flask学习记录 —— Flask视图函数

flask视图函数,基于菜鸟教程

qq_39991776的博客 1555

菜鸟学习笔记-MPChart动态添加

Android-MPchart动态添加 菜鸟初学,自己根据大佬的代码学习整理的,适合刚学MPchart的看 在进行动态添加前要设置一个linedata LineData lineData=new LineData(); lineChart.setData(lineData); 这样就会在程序里显示一个空白的框 1.添加一个点 LineData data=lineC...

hanmoliuxuan的博客 1275

80386汇编

80386汇编知识 与汇编语言略有不同,是一门全新的编程语言,尽管继承了汇编语言的语法. 80836寄存器 通用寄存器(EAX EBX ECX EDX,ESP,EBP,ESI,EDI) 段寄存器(CS SS DS ES FS GS) 指令寄存器和变址寄存器(EIP EFLAGS) 系统地址寄存器(GDTR IDTR LDTR … 控制寄存器(CR0 CR1 CR2 CR3 CR4) 调试寄存器...

lonmar的博客 2220

汇编(伪指令与源程序格式)

汇编三种语句:指令,伪指令,宏指令 指令程序中由cpu执行,伪指令在汇编期间由汇编程序执行 *处理器选择伪指令 .8086 8086指令系统 .286 80286指令系统 .286p 保护下的80286指令系统 .386 80386指令系统 段定义伪指令 masm5.0支持简化的段定义方法: mode small //定义存储模型 data //定义数据段 string db...

weixin_46045444的博客 1206

小小Bootkit(2)

BootKit之VirusMbr Sjtujg 先介绍一些关于MBR的基础知识,Bios加电之后选择引导介质(一般是磁盘),如果选择了磁盘,就将磁盘的第一个扇区的内容读入到内存中,然后流程转向执行这部分代码,磁盘的第一个扇区就是我们所说的MBR.MBR的内容有512个字节,其中可执行的代码内容只有400多字节,还有64个字节是磁盘分区表,计算机凭借分区表来选择引导分区,并将其第一个扇区(引导扇

sjtujgxxaq的专栏 1201

菜鸟的病毒分析2

dos 运行期.exe文件感染病毒 还是如此的菜原谅我吧 病毒行为:感染.com文件 修改被感染文件的SS:SP流程:恢复被感染的文件的 cs:ip ss:sp 搜索.exe 如果是正确的.exe文件并且没有被感染过 ,打开文件保存文件信息 ,进行感染修改测试:ip ss:sp, 添加病毒代码 ,恢复文件信息 ,关闭文件用到的中断与上篇.com文件的感染相同dos下com文件与exe文件...

abcd8080的博客 301

深度挖掘boot-----mbr启动代码分析

这次自己分析一遍MBR,先拿winhex把MBR弄出来,保存到mbr.bin,再用IDA分析winhex弄出来的样子:下面先贴流程图代码中设计几个bios中断调用:INT 13,8 - Get Current Drive Parameters (XT & newer)        AH = 08        DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)        on return:        AH =

jizhongqing的专栏 4193

80386ASM程序设计基础()

主要介绍段描述符,段选择子   在保护模式下,段是实现虚拟地址到线性地址转换的基础。在保护方下,每个段有三个参数:段基址,段界限,段属性。段基址规定了线性地址空间中段的开始地址,段基址长度为32位,所以任何一个段都可以从32位线性地址空间中的任何一个字节开始,这一点和实式方式不同,实式方式下要求段的边界必须被16整除。段界限规定段的大小,段界限用20位表示,而且段界限可以是字节或4K为单位,这个称

kingcaiyao的专栏 1911

Pico PIO 汇编语法深度详解:标识符、指令、伪指令全解析

PIO汇编(pioasm)语法包括标识符、数据类型、表达式、注释、标签、指令和伪指令。标识符定义结构与配置;标签是汇编器自动生成的偏移量定义;指令支持侧集和延时;伪指令nop由汇编器转换为mov y,y,用于侧集、延时或占位。

weixin_44719294的博客 18
上一篇: 【转贴】80386ASM程序设计基础(七)
下一篇: 【转贴】80386ASM程序设计基础(九)
TalosChen
博客等级 码龄23年 1粉丝 4原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值