汇编学习

编译问题

由于现在的计算机是64位,而debug是当年在16位的计算机上搞的,在32位计算机中,微软还在系统同增加了debug这个工具,但是到了64位,却没有加,所以我们要自己去下载一个 dosbox 开源的dos模拟器,然后将debug在dosbox中运行。当然这些都是没问题的。问题是:

在下载masm后,由于第一次接触,编写好源程序后,用指令 masm xxx。asm 。但是一直报 A2044的错误,就百度,知乎,都说输入的格式错误,或者有非法字符。但是确定了没有之后还是报错,就这样痛苦了一晚上,第二天起来,还是不知道为什么,就抱着试一试(奔溃了),换了个masm版本,这次成功了。 但是在编写一个新的源程序,又是这个错误,再次崩,()/(ㄒoㄒ)/~~。

突然我想到,会不会是编码格式的错误呢,就换了UTF-8试一下,果然。。。

既然网上都说了格式或者非法字符,那怎么没想到编码问题呢。

一些指令记录

  • and指令:OR是按位“或”操作。但是可以用来表示inc操作,比如 0 and 3 = 0,1 and 3 = 1,2 and 3 = 2,3 and 3 = 3,4 and 3 = 0,5 and 3 = 1,以此做 0-3 的循环。

  • not指令:按位取反。根据计算机中存储数据都是补码形式,所以我们用运算符对一个数取相反数要(a+1),注意有一个加1。

  • sal指令:算数左移,移了的位用0填充。移动一位相当于乘2。与逻辑左移相同。

  • sar指令:算数右移,将数据向右移位,移了的位用符号位填充。如10000000算术右移1位后就成:11000000。移动一位相当于除2,不用考虑余数。 比如 eax = 3 (11) , sar eax,1 后 eax = (01) = 1,相当于 3/2 = 1。

  • ror指令:循环右移,把所有位都向右移,最低位复制到进位标志位和最高位。指令用C语言来实现:如 ror a,3 对应 ((a>>3)| ((a&7) << 5))

    image-20200529164348298

  • rol指令:循环左移,与ror类似。

  • neg:NEG命令无论你是否为正负数,都会按照取反+1或用0减去这个bai数的二进制的办法去计算。当操作数为0时,置CF位为0;当操作数不为0时,置CF位为1。intel手册:The CF flag set to 0 if the source operand is 0; otherwise it is set to 1。 The OF,SF,ZF,AF,and PF flags are set according to the result。

  • sbb:带借位减法指令,它利用了CF位上记录的借位值。指令格式:sbb 操作对象1,操作对象2;功能:操作对象1 = 操作对象1 - 操作对象2 - 1;

  • 指令同义名效果设置条件
    sete DsetzD = ZF相等/零
    setne DsetnzD = ~ZF不等/非零
  • cdq:这个指令把 EAX 的第 31 bit 复制到 EDX 的每一个 bit 上。 它大多出现在除法运算之前。它实际的作用只是把EDX的所有位都设成EAX最高位的值。也就是说,当EAX <80000000,EDX 为00000000;当EAX >= 80000000, EDX 则为FFFFFFFF。

    例如 :

     假设 EAX 是 FFFFFFFB (-5) ,它的第 31 bit (最左边) 是 1,
     执行 CDQ 后, CDQ 把第 31 bit 复制至 EDX 所有 bit
     EDX 变成 FFFFFFFF
    这时候, EDX:EAX 变成 FFFFFFFF FFFFFFFB ,它是一个 64 bit 的大型数字,数值依旧是 -5。

    备注:

    ​ EDX:EAX,这里表示EDX,EAX连用表示64位数

  • xchg:寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同,可以是一个字节,也可以是一个字,也可以是双字。

  • shr 与shl:shl和shr是逻辑移位指令,shl是逻辑左移指令,它的功能为:(1)将一个寄存器或内存单元中的数据向左移位;(2)将最后移出的一位写入CF中;(3)最低位用0补充。shr是逻辑右移指令,它和shl所进行的操作刚好相反。

  • das:组合(压缩)BCD码的加法调整指令。使用DAS指令时,通常先执行SUB/SBB指令,将两个压缩BCD码相减,结果存放在AL中。功能:如果AL低四位>9或AF=1 ,则AL的值减06h,并置AF=1;如果AL高四位>9或CF=1 ,则AL的值减60h ,且置CF=1;

  • cdq:cdq的作用无非就是将一个32位有符合数扩展为64位有符合数,数据能表示的数不变,具体是这样实现的,比如eax=fffffffb(值为-5),然后cdq把eax的最高位bit,也就是二进制1,全部复制到edx的每一个bit位,EDX 变成 FFFFFFFF,这时eax与edx连起来就是一个64位数,FFFFFFFF FFFFFFFB ,它是一个 64 bit 的大型数字,数值依旧是 -5。

小端问题

  • 在程序密码算法时,可能会将计算后的数据存放在4个内存单元,然后将其传给一个通用寄存器(EAX),但是一般英特尔的cpu,数据存放形式都是小端,所以会将该4个内存单元的数据,以它小端存储方式读取,比如,4个连续内存单元的数据依次为 0x12 0x34 0x56 0x78,传给寄存器后,由于小端,所以为,0x78563412。 那么我们再写注册机的时候就可以,先定义一个联合:

    1
    2
    3
    4
    5
    6
    union EAX
    {
    int eax;

    unsigned char[4];
    }

    依次,将4个数据存放在char[0 - 3] ,而eax就是我们要得值了。 (不过这里要注意使用unsigned char ,因为一个字节的最大数据为 2 ^8 - 1 (FF), 有符号char 是 -2^7 ~ 2^7-1 ,用有符号char 很容易溢出)。

-------------本文结束感谢您的阅读-------------