逆向——汇编中的位运算

 

汇编中的移位指令

1、算术移位指令

 

SAL(算术左移)指令的操作与《SHL指令》一节中的 SHL 指令一样。每次移动时,SAL 都将目的操作数中的每一位移动到下一个最高位上。最低位用 0 填充;最高位移入进位标志位,该标志位原来的值被丢弃:


如,二进制数 1100 1111 算术左移一位,得到 1001 1110:


SAR(算术右移)指令将目的操作数进行算术右移:

  • SAL(Shift Arithmetic Left):算术左移

  • SAR(Shift Arithmetic Right):算术右移

  • 格式:SAL/SAR Reg/Mem, CL/Imm

即算数移位指令后面的第一个操作数是寄存器或者内存;

第二个操作数是寄存器或者立即数

SAL eax,2
SAL ax,1
SAL al,3


举例:
SAR al,1         //al:10000001右移一位最高位补原来符号位,最低位移入CF,即11000000 / CF:1
SAL al,2         //al:10000001左移两位最高位移入CF,最低位补0,即00000100 /  CF:0


2.逻辑移位指令

SHL(左移)指令使目的操作数逻辑左移一位,最低位用 0 填充。最高位移入进位标志位,而进位标志位中原来的数值被丢弃:


若将 1100 1111 左移 1 位,该数就变为 1001 1110:

mov dl, 10           ;移动前:00001010
shl dl, 2               ;移动后:00101000
 

 SHR(右移)指令使目的操作数逻辑右移一位,最高位用 0 填充。最低位复制到进位标志位,而进位标志位中原来的数值被丢弃:

  • SHL(Shift Left):逻辑左移

  • SHR(Shift Right):逻辑右移

  • 格式:SHL/SHR Reg/Mem, CL/Imm

    SHL eax,2
    SHR word ptr es:[ebp],1
    SHL al,1

    举例:
    SHR al,1         //al:10000001右移一位最高位补0,最低位移入CF,即01000000 /  CF:1
    SHL al,1         //al:01000001左移一位最高位移入CF,最低位补0,即10000010 /  CF:0

     

  • shl/sal区别?这样一看,似乎SHL和SAL指令是完全一样的
    区别在于,SHL是逻辑左移SAL是算术左移

SAL算术移位需要考虑最高位的符号位,要保证移到后的最高位,也就是符号位不变。用于带符号数的运算。
最高位符号位移入CF,但本身保持原值,其余位顺序左移,次高位被舍弃。

SHL逻辑移不用考虑直接移就ok。所有位顺序左移,最高位移入CF,最低位补0。用于无符号数的计算

 

3.循环移位指令

 以循环方式来移位即为位元循环(Bitwise Rotation)。一些操作中,从数的一端移出的位立即复制到该数的另一端。还有一种类型则是把进位标志位当作移动位的中间点。

ROL(循环左移)指令把所有位都向左移。最高位复制到进位标志位和最低位。该指令格式与 SHL 指令相同:


位循环不会丢弃位。

ROR(循环右移)指令把所有位都向右移,最低位复制到进位标志位和最高位。该指令格式与 SHL 指令相同:

 

  • ROL(Rotate Left):循环左移

  • ROR(Rotate Right):循环右移

  • 格式:ROL/ROR r/m, i8/CL

    ROL eax,3
    ROL cx,1
    ROR cl,2

    举例
    ROL al,1   //al:10000001循环左移一位最高位补到最低位,最高位移入CF,即00000011 /  CF:1
    ROR al,1   //al:10000001循环右移一位最低位补到最高位,最低位移入CF,即11000000 /  CF:1

4.带进位的循环移位指令

 

  • RCL(Rotate through Carry Left):带进位循环左移

  • RCR(Rotate through Carry Right):带进位循环右移

  • 格式:RCL/RCR r/m, i8/CL

RCL eax,1
RCR cx,2
RCR al,1

举例:
RCL al,1 //al:10000001,CF:0循环左移一位最高位移入CF,CF原来的数补到最低位,即al:00000010 / CF:1
RCR al,1 //al:10000001,CF:0循环右移一位最低位移入CF,CF原来的数补到最高位,即al:01000000 / CF:1

C语言中的移位运算

与运算 &

printf("%d",2&3); //2

或运算 |

printf("%d",2|3); //3

非运算 ~

printf("%d",~2); //-3,因为%d打印的是有符号的整数

异或运算 ^

printf("%d",2^3); //1

移位运算 << >>

左移运算,有符号和无符号是无区别的

int a = 8;
printf("%d",a<<1);  //16
unsigned int b = 8;
printf("%d",b<<1);  //16

查看反汇编:生成的汇编指令都是shl,逻辑左移

img

右移运算,有符号对应SAR即算数右移,无符号对应SHR即逻辑右移

int a = 0xF0000000;
printf("%d",a>>1);  //-134217728
unsigned int b = 0xF0000000;
printf("%d",b>>1);  //2013265920

查看反汇编:有符号右移生成的指令为SAR,无符号右移生成的指令为SHR

img

作业【有错,pass吧】

 

复制代码
#include "stdafx.h"
​
​
    void Function_1_1()     
    {
            unsigned char x=0xf5,y=0xff;
            int i;
            scanf("%d",&i);
        /*  if((x=x&(y<<i))==0)
                (printf("第%d位是0",i+1));
            else
                (printf("第%d位是1",i+1));
*/
    printf("第%d位是%x",i,x=x&(y>>(8-i))); 
        //  printf("%x",x);
            
    }       
​
​
​
int main()
{           
​
        Function_1_1();             
​
    return 0;
​
}
 
复制代码

 

16:       unsigned char x=0xf5,y=0xff;
0040D830   mov         byte ptr [ebp-0Ch],0F5h
0040D834   mov         byte ptr [ebp-10h],0FFh
17:       int i;
18:       scanf("%d",&i);
0040D838   lea         ecx,[ebp-14h]
0040D83B   push        ecx
0040D83C   push        offset string "112" (00422134)
0040D841   call        scanf (0040faa0)
0040D846   add         esp,8
19:   /*  if((x=x&(y<<i))==0)
20:           (printf("第%d位是0",i+1));
21:       else
22:           (printf("第%d位是1",i+1));
23:   */
24:       printf("第%d位是%x",i,x=x&(y>>(8-i)));
0040D849   mov         edx,dword ptr [ebp-0Ch]
0040D84C   and         edx,0FFh
0040D852   mov         eax,dword ptr [ebp-10h]
0040D855   and         eax,0FFh
0040D85A   mov         ecx,8
0040D85F   sub         ecx,dword ptr [ebp-14h]
0040D862   sar         eax,cl;//********************关键**************
0040D864   and         edx,eax
0040D866   mov         byte ptr [ebp-0Ch],dl
0040D869   mov         ecx,dword ptr [ebp-0Ch]
0040D86C   and         ecx,0FFh
0040D872   push        ecx
0040D873   mov         edx,dword ptr [ebp-14h]
0040D876   push        edx
0040D877   push        offset string "%d\n" (0042201c)
0040D87C   call        printf (00401120)
0040D881   add         esp,0Ch

 

 

 

看来这个小伙做错了!!!

 

  • 用十六进制文本编辑器分别打开一个.exe、.dll、.sys、.txt、.doc、.jpg、.pdf等将前两个字节写在下面

.exe:内存中显式为4D 5A,我们读作0x5A4D .dll:同样是4D 5A .sys:4D 5A开头,但也有25 75 .txt:0A 66,读作0x660A .doc:D0 CF,读作0xCFD0 .jpg:FF D8 .pdf:25 50,读作0x5025

  • 将一个在十六进制编辑器中打开的.exe文件,拖拽到最后,观察文件中的大小和硬盘上的大小

可以发现用十六进制编辑器打开一个.exe文件,它的最大地址0x0829CDF0,换算成10进制,就刚好等于这个文件的大小136957440字节 img

 
分类: 逆向-PE
posted @ 2023-04-05 16:59  bonelee  阅读(790)  评论(0编辑  收藏  举报