滴水PE前漏洞

1. 只用逻辑运算2-3=?

2-3=-1   #用计算机的逻辑运算本质运算
X:0010   #将2存入容器X
Y:1101   #将-3存入容器Y
     0010
 xor 1101    #异或
     1111    #值为-1
     
     0010
   & 1101
     0000   #与运算后得出0
     
 0000 <<1 == 0000   #左移一位还是0000,得出结果就是1111-1

2. 标志寄存器的位置

标志寄存器位置

  1. 进 位 标 志 C F ( C a r r y F l a g ) \color{blue}{进位标志CF(Carry Flag)} CF(CarryFlag):如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0;

  2. 辅 助 进 位 标 志 A F ( A u x i l i a r y C a r r y F l a g ) \color{blue}{辅助进位标志AF(Auxiliary Carry Flag)} AF(AuxiliaryCarryFlag)

    在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:

    (1)、在字操作时,发生低字节向高字节进位或借位时;

    (2)、在字节操作时,发生低4位向高4位进位或借位时

  3. 溢 出 标 志 O F ( O v e r f l o w F l a g ) \color{blue}{溢出标志OF(Overflow Flag)} OF(OverflowFlag):溢出标志OF用于反映有符号数加减运算所得结果是否溢出。
    如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。

注:

		最高位进位与溢出的区别:
>进位标志表示无符号数运算结果是否超出范围.
>溢出标志表示有符号数运算结果是否超出范围.
>OF位溢出主要是给有符号运算使用的,在有符号的运算中,有如下的规律:	
>正 + 正 = 正 如果结果是负数,则说明有溢出
>负 + 负 = 负 如果结果是正数,则说明有溢出
>正 + 负 永远都不会有溢出.

示例


3. CPU是如何计算2+3=?

2+3 = ?                            
                                 
    X:0010                                                         
    Y:0011    R:0001                        
                                
       0010               0001                
xor    0011        xor    0100    R:0101            
 -------------        ---------------                    
       0001            	  0101    5            
                                
                                
      0010           	  0001                
&     0011           &    0100                
 ------------    	------------                
      0010          	  0000                
                                
0010 << 1 == 0100            0000<<1 == 0000                 
                                                                
    X:0001                                     
    Y:0100                            

4. 获取某个值的第N位的值是多少?

如:8F

 如:8F                            
        		   10001111                        
          and 	   00001000    
          		-----------                    
  			       00001000      

5. 常见的几种调用约定

调用约定


6. console程序入口查找

  • 程序真正的入口

    main 或 Winmain 是“语法规定的用户入口”,而不是“应用程序的入口”,应用程序的入口通常是start函数
    识别前的调用


7. 变量的特点

局部与全局


8. 参数传递的问题

  • 参数传递不仅仅是 push 之后

    1.观察调用函数
    2.找平衡堆栈的代码(内部 ret 或外部 add esp 0x~)

  • 其它方式
    其它方式


9. if…else…反汇编练习

练习一

练习代码

  • 函数内部变量分析

    1. 分析参数:
    	[ebp + 8]:x
    	[ebp + 0xC]:y
    2. 分析局部变量
    	[ebp - 4]:a
    	[ebp - 8]:b = 23. 分析全局变量
    	[004225c4]:k
    
  • 函数功能分析
    功能分析

  • 还原c语言代码

    #include<stdio.h>
    
    int k;
    void plus(int x,int y)
    {
    	int a = k;
    	int b = 2;
    	if(x >= y)
    	{
    		b = b +1;
    		if(x < y)
    		{
    			k = b;
    		}
    	}
    	else
    	{
    		k = a+ b;
    	}
    }
    int main(int argc,char* argv[])
    {
    	plus(3,6);
    	//getchar();
    	return 0;
    }
    

    练习二

    if...else..练习二


10. 类型转换

扩展

  • 发现一个 c 代码没写过,有点新奇
    int age[5][10] = {
    {1,2,3,4,5,6,7,8,9,10},                        
    {21,22,23,24,25,26,27,28,29,30},                        
    {31,32,33,34,35,36,37,38,39,40},                        
    {41,42,43,44,45,46,47,48,49,50},                        
    {51,52,53,54,55,56,57,58,59,60}        
    };            
    
    void fun(){
     for (int i=0;i<5;i++)
    	{
        	for (int j=0;j<9;j++) //这里是前面一个数组加后面一个,到了倒数第二个的时候刚好把最后一个加上去了,所以是j<9
       		 {
            	age[i][0] = age[i][0] + age[i][j+1]; //这里j+1意思就是前面一个数组加后面一个数组
        	}
        }
    
     for (int k=0;k<5;k++)
    	 	{
        	printf("%d \n",age[k][0]);
    		}
    }
    

11. 循环

while
for
详见


12. 64位存储方式

  • 返回值超过32位时,存在哪里?用long long(__int64)类型做实验
    long long类型在VC6中对应的是__int64
    
    __int64 Function()
    {
       __int64 x = 0x1234567890; 
       return x;
    }
    

    >>>>64位存储方式是连续存储高字节的存在ebp-8里面,低字节的存在ebp-c里面,返回值是通过eax,dex寄存器返回的


13. 结构体作为返回值

struct st1 
{
    int a;
    int b;
};
 struct st    
    {    
	char a4;
    short b4;
    int c4;
    int arr4[10];
    st1 d4;
    };    
    st Function()    
    {    
        st s;
		st.a4 = 6;				//		mov   byte ptr [ebp-50h],6
    	st.arr4[2] = 76;		//		mov   dword ptr [ebp-40h],4Ch
    	st.b4 = 5;				//		mov   word ptr [ebp-4Eh],offset fun+60h (0040b9e0)
    	st.c4 = 88;				//		mov   dword ptr [ebp-4Ch],58h
    	st.d4.a = 90;			//		mov   dword ptr [ebp-20h],5Ah
        return s;			//  mov   ecx,0Eh ;lea  esi,[ebp-50h] ;mov edi,dword ptr [ebp+8] ;rep movs  dword ptr [edi],dword ptr [esi] ;mov  eax,dword ptr [ebp+8]
    };    
    int main(int argc, char* argv[]) 
    {    
        st s = Function(); 
        return 0;
    }    

14. movs 与 stos 指令

  • M O V S \color{blue}{MOVS} MOVS指令:移动数据 内存-内存

    BYTE/WORD/DWORD
    MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ~~~~~简写为:MOVSB
    MOVS WORD PTR ES:[EDI],BYTE PTR DS:[ESI] ~~~~~简写为:MOVSW
    MOVS DWORD PTR ES:[EDI],BYTE PTR DS:[ESI] ~~~~~简写为:MOVSD

  • S T O S \color{blue}{STOS} STOS指令:讲Al/AX/EAX的值存储到[EDI]指定的内存单元
    STOS BYTE PTR ES:[EDI] ~~~~~简写为STOSB
    STOS WORD PTR ES:[EDI] ~~~~~简写为STOSW
    STOS DWORD PTR ES:[EDI] ~~~~~简写为STOSD
    详见

15. switch反汇编

  • case 小于等于3时同 if…else…

  • case 大于3时会生成对应的大表

    1:    void fun(int x)
    2:    {
    0040B800   push        ebp
    0040B801   mov         ebp,esp
    0040B803   sub         esp,44h
    0040B806   push        ebx
    0040B807   push        esi
    0040B808   push        edi
    0040B809   lea         edi,[ebp-44h]
    0040B80C   mov         ecx,11h
    0040B811   mov         eax,0CCCCCCCCh
    0040B816   rep stos    dword ptr [edi]
    3:        switch (x)
    4:       {
    0040B818   mov         eax,dword ptr [ebp+8]
    0040B81B   mov         dword ptr [ebp-4],eax
    0040B81E   mov         ecx,dword ptr [ebp-4]
    0040B821   sub         ecx,64h
    0040B824   mov         dword ptr [ebp-4],ecx
    0040B827   cmp         dword ptr [ebp-4],9
    0040B82B   ja          $L815+0Fh (0040b8d7)
    0040B831   mov         edx,dword ptr [ebp-4]
    0040B834   jmp         dword ptr [edx*4+40B8F5h]
    5:       case 100:
    6:           printf("100\n");
    0040B83B   push        offset string "100\n" (00420fc8)
    0040B840   call        printf (00401110)
    0040B845   add         esp,4
    7:           break;
    0040B848   jmp         $L815+1Ch (0040b8e4)
    8:       case 101:
    9:           printf("101\n");
    0040B84D   push        offset string "101\n" (00420fc0)
    0040B852   call        printf (00401110)
    0040B857   add         esp,4
    10:           break;
    0040B85A   jmp         $L815+1Ch (0040b8e4)
    11:       case 102:
    12:           printf("102\n");
    0040B85F   push        offset string "102\n" (00420fb8)
    0040B864   call        printf (00401110)
    0040B869   add         esp,4
    13:           break;
    0040B86C   jmp         $L815+1Ch (0040b8e4)
    14:       case 103:
    15:           printf("103\n");
    0040B86E   push        offset string "103\n" (00420f84)
    0040B873   call        printf (00401110)
    0040B878   add         esp,4
    16:           break;
    0040B87B   jmp         $L815+1Ch (0040b8e4)
    17:       case 104:
    18:           printf("104\n");
    0040B87D   push        offset string "104\n" (00420fb0)
    0040B882   call        printf (00401110)
    0040B887   add         esp,4
    19:           break;
    0040B88A   jmp         $L815+1Ch (0040b8e4)
    20:       case 105:
    21:           printf("105\n");
    0040B88C   push        offset string "105\n" (00420fa8)
    0040B891   call        printf (00401110)
    0040B896   add         esp,4
    22:           break;
    0040B899   jmp         $L815+1Ch (0040b8e4)
    23:       case 106:
    24:           printf("106\n");
    0040B89B   push        offset string "106\n" (00420fa0)
    0040B8A0   call        printf (00401110)
    0040B8A5   add         esp,4
    25:           break;
    0040B8A8   jmp         $L815+1Ch (0040b8e4)
    26:       case 107:
    27:           printf("107\n");
    0040B8AA   push        offset string "107\n" (00420f98)
    0040B8AF   call        printf (00401110)
    0040B8B4   add         esp,4
    28:           break;
    0040B8B7   jmp         $L815+1Ch (0040b8e4)
    29:       case 108:
    30:           printf("108\n");
    0040B8B9   push        offset string "108\n" (00420024)
    0040B8BE   call        printf (00401110)
    0040B8C3   add         esp,4
    31:           break;
    0040B8C6   jmp         $L815+1Ch (0040b8e4)
    32:       case 109:
    33:           printf("109\n");
    0040B8C8   push        offset string "109\n" (00420f90)
    0040B8CD   call        printf (00401110)
    0040B8D2   add         esp,4
    34:           break;
    0040B8D5   jmp         $L815+1Ch (0040b8e4)
    35:       default:
    36:           printf("Error\n");
    0040B8D7   push        offset string "Error\n" (0042001c)
    0040B8DC   call        printf (00401110)
    0040B8E1   add         esp,4
    37:           break;
    38:       }
    39:   }
    0040B8E4   pop         edi
    0040B8E5   pop         esi
    0040B8E6   pop         ebx
    0040B8E7   add         esp,44h
    0040B8EA   cmp         ebp,esp
    0040B8EC   call        __chkesp (00401190)
    0040B8F1   mov         esp,ebp
    0040B8F3   pop         ebp
    0040B8F4   ret
    0040B8F5   cmp         edi,dword ptr [eax-47B2FFC0h]
    0040B8FB   inc         eax
    0040B8FC   add         byte ptr [edi-48h],bl
    0040B8FF   inc         eax
    0040B900   add         byte ptr [esi-48h],ch
    0040B903   inc         eax
    0040B904   add         byte ptr [ebp-48h],bh
    0040B907   inc         eax
    0040B908   add         byte ptr [eax+edi*4-4764FFC0h],cl
    0040B90F   inc         eax
    0040B910   add         byte ptr [edx-46FFBF48h],ch
    0040B916   mov         eax,0B8C80040h
    0040B91B   inc         eax
    0040B91C   add         ah,cl
    
  • 根据大表计算

    64 - - 十进制 100
    106-100 = 6
    edx*4+40B8F5h
    从上面计算公式得出
    6×4+40B8F5 意思就是0040B8F5所在的大表向下以4个字节移动6位

  • 大表

    0040B8F5 3B B8 40 00
    0040B8F9 4D B8 40 00
    0040B8FD 5F B8 40 00
    0040B901 6E B8 40 00
    0040B905 7D B8 40 00
    0040B909 8C B8 40 00
    0040B90D 9B B8 40 00
    0040B911 AA B8 40 00
    0040B915 B9 B8 40 00
    0040B919 C8 B8 40 00

  • 向下以4字节移动6位刚好就是大表地址 0040B90D 9B B8 40 00 对应的内存地址: 0040B89B

    23: printf(“106\n”);
    0040B89B push offset string “106\n” (00420fa0)
    0040B8A0 call printf (00401110)
    0040B8A5 add esp,4

  • 此时去掉 c a s e 108 \color{orange}{case 108} case108,则生成的大表为

    0040B8F5 3B B8 40 00
    0040B8F9 4D B8 40 00
    0040B8FD 5F B8 40 00
    0040B901 6E B8 40 00
    0040B905 7D B8 40 00
    0040B909 8C B8 40 00
    0040B90D 9B B8 40 00
    0040B911 AA B8 40 00
    0040B915 B9 B8 40 00         将变为 D7 B8 40 00
    0040B919 C8 B8 40 00

  • 结论

    1. 当抹去case语句小于等于5个时,会将default的内存地址编号放入大表中;
    2. 当抹去6个case语句的时候会生成小表(case较多但连续性不是太好)
      7:    void fun(int x)
      8:    {
      0040B800   push        ebp
      0040B801   mov         ebp,esp
      0040B803   sub         esp,44h
      0040B806   push        ebx
      0040B807   push        esi
      0040B808   push        edi
      0040B809   lea         edi,[ebp-44h]
      0040B80C   mov         ecx,11h
      0040B811   mov         eax,0CCCCCCCCh
      0040B816   rep stos    dword ptr [edi]
      9:        switch (x)
      10:       {
      0040B818   mov         eax,dword ptr [ebp+8]
      0040B81B   mov         dword ptr [ebp-4],eax
      0040B81E   mov         ecx,dword ptr [ebp-4]
      0040B821   sub         ecx,64h
      0040B824   mov         dword ptr [ebp-4],ecx
      0040B827   cmp         dword ptr [ebp-4],9
      0040B82B   ja          $L803+0Fh (0040b87b)
      0040B82D   mov         eax,dword ptr [ebp-4]
      0040B830   xor         edx,edx
      0040B832   mov         dl,byte ptr  (0040b8ad)[eax]
      0040B838   jmp         dword ptr [edx*4+40B899h]
      11:       case 100:
      12:           printf("100\n");
      0040B83F   push        offset string "100\n" (00420fa0)
      0040B844   call        printf (00401110)
      0040B849   add         esp,4
      13:           break;
      0040B84C   jmp         $L803+1Ch (0040b888)
      14:       case 101:
      15:           printf("101\n");
      0040B84E   push        offset string "101\n" (00420f98)
      0040B853   call        printf (00401110)
      0040B858   add         esp,4
      16:           break;
      0040B85B   jmp         $L803+1Ch (0040b888)
      17:       case 102:
      18:           printf("102\n");
      0040B85D   push        offset string "104\n" (00420024)
      0040B862   call        printf (00401110)
      0040B867   add         esp,4
      19:           break;
      0040B86A   jmp         $L803+1Ch (0040b888)
      20:
      21:
      22:       case 109:
      23:           printf("109\n");
      0040B86C   push        offset string "109\n" (00420f90)
      0040B871   call        printf (00401110)
      0040B876   add         esp,4
      24:           break;
      0040B879   jmp         $L803+1Ch (0040b888)
      25:       default:
      26:           printf("Error\n");
      0040B87B   push        offset string "Error\n" (0042001c)
      0040B880   call        printf (00401110)
      0040B885   add         esp,4
      27:           break;
      28:       }
      29:   }
      0040B888   pop         edi
      0040B889   pop         esi
      0040B88A   pop         ebx
      0040B88B   add         esp,44h
      0040B88E   cmp         ebp,esp
      0040B890   call        __chkesp (00401190)
      0040B895   mov         esp,ebp
      0040B897   pop         ebp
      0040B898   ret
      0040B899   aas
      0040B89A   mov         eax,0B84E0040h
      0040B89F   inc         eax
      0040B8A0   add         byte ptr [ebp-48h],bl
      0040B8A3   inc         eax
      0040B8A4   add         byte ptr [eax+edi*4+40h],ch
      0040B8A8   add         byte ptr [ebx-48h],bh
      0040B8AB   inc         eax
      0040B8AC   add         byte ptr [eax],al
      0040B8AE   add         dword ptr [edx],eax
      0040B8B0   add         al,4
      0040B8B2   add         al,4
      0040B8B4   add         al,4
      0040B8B6   add         ecx,esp
      
    • 对应的大表和小表

      0040B899 3F B8 40 00
      0040B89D 4E B8 40 00
      0040B8A1 5D B8 40 00
      0040B8A5 6C B8 40 00
      0040B8A9 7B B8 40 00
      0040B8AD 00 01 02 04 //小表
      0040B8B1 04 04 04 04 //小表
      0040B8B5 04 03 CC CC //小表

    • 其中反汇编 0040B832 mov dl,byte ptr (0040b8ad)[eax] 含义

      将小表0040B8AD加上eax的值,就是结果,而eax值此时是6,所以向后移动6位即可

      0040B8AD 00 01 02 04
      0040B8B1 04 04 04 04

      00 01 02 04 04 04 04 04 —> 向后移动6位,就是数6位,得到的结果是04,所以edx的结果是4 根据下面的公式

      edx*4+40B899h 4×4+0040B899 可以得出结果是以4字节向后4位即可得到计算结果的内存地址编号:0040B8A9 7B B8 40 00

      内存编号对应的内存地址:0040B87B

  1. 当case后的常量差距较大时,编译器仍按照if…else…进行反汇编

16. 指针

  1. 带*类型的变量可以加、减一个整数,但不能乘或者除.

  2. 带*类型变量与其他整数相加或者相减时:

    类型变量 + N = 带类型变量 + N*(去掉一个后类型的宽度)
    类型变量 - N = 带类型变量 - N(去掉一个*后类型的宽度)

    例:9:        char** a;
    10:       short** b;
    11:       int** c;
    12:
    13:       a = (char**)100;
    0040B818   mov         dword ptr [ebp-4],64h
    14:       b = (short**)100;
    0040B81F   mov         dword ptr [ebp-8],64h
    15:       c = (int**)100;
    0040B826   mov         dword ptr [ebp-0Ch],64h
    16:
    17:
    18:       a++;
    0040B82D   mov         eax,dword ptr [ebp-4]
    0040B830   add         eax,4                // 104
    0040B833   mov         dword ptr [ebp-4],eax
    19:       b++;
    0040B836   mov         ecx,dword ptr [ebp-8]
    0040B839   add         ecx,4              // 104
    0040B83C   mov         dword ptr [ebp-8],ecx
    20:       c++;
    0040B83F   mov         edx,dword ptr [ebp-0Ch]
    0040B842   add         edx,4              // 104
    0040B845   mov         dword ptr [ebp-0Ch],edx
    
  • 寻找对应地址
    #include<stdio.h>
    
    char data[] = {
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x09,
    0x00,0x20,0x10,0x03,0x03,0x0C,0x00,0x00,0x44,0x00,
    0x00,0x33,0x00,0x47,0x0C,0x0E,0x00,0x0D,0x00,0x11,
    0x00,0x00,0x00,0x02,0x64,0x00,0x00,0x00,0xAA,0x00,
    0x00,0x00,0x64,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x02,0x00,0x74,0x0F,0x41,0x00,0x00,0x00,
    0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,
    0x00,0x02,0x74,0x0F,0x41,0x00,0x06,0x08,0x00,0x00,
    0x00,0x00,0x00,0x64,0x00,0x0F,0x00,0x00,0x0D,0x00,
    0x00,0x00,0x23,0x00,0x00,0x64,0x00,0x00,0x64,0x00
    };
    // type: byte     num: data
    void search_int(int num, int length)
    {
        int i = 0;
        while (i < length - 4)
        {
            if (*(int*)&data[i] == num)
            {
                printf("address:%x , data:%d\n", &data[i], (int)num);
            }
            i++;
        }
    }
    void search_short(int num, int length)
    {
        int i = 0;
        while (i < length - 2)
        {
            if (*(short*)&data[i] == num)
            {
                printf("address:%x , data:%d\n", &data[i], (short)num);
            }
            i++;
        }
    }
    
    void search_char(int num, int length)
    {
        int i = 0;
        while (i < length - 1)
        {
            if (*(char*)&data[i] == num)
            {
                printf("address:%x , data:%d\n", &data[i], (char)num);
            }
            i++;
        }
    }
    void search(int type, int num)
    {
        int length = sizeof(data) / sizeof(data[0]);
        int i = 0;
        typedef void (*funcptr)(int, int);
        funcptr p;
        if (type == 4)
        {
            p = search_int;
        }
        else if (type == 2)
        {
            p = search_short;
        }
        else
        {
            p = search_char;
        }
        p(num, length);
    }
    
    int main(int argc, char* argv[])
    {
        printf("data start from:%x\n", data);
        search(4, 0x64);
        return 0;
    }
    
  • 再来一个吧
			typedef struct TagPlayer
		{
		    int id;
		    int level;
		}Player;
		
		char data[] = {
		0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x09,
		0x00,0x20,0x10,0x03,0x03,0x0C,0x00,0x00,0x44,0x00,
		0x00,0x33,0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x02,0x64,0x00,0x00,0x00,0xAA,0x00,
		0x00,0x00,0x64,0x01,0x00,0x00,0x00,0x08,0x00,0x00,
		0x00,0x00,0x02,0x00,0x74,0x0F,0x41,0x00,0x00,0x00,
		0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,
		0x00,0x02,0x57,0x4F,0x57,0x00,0x06,0x08,0x00,0x00,
		0x00,0x00,0x00,0x64,0x00,0x0F,0x00,0x00,0x0D,0x00,
		0x00,0x00,0x23,0x00,0x00,0x64,0x00,0x00,0x64,0x00
		};
		
		void search_Struct()
		{
		    int i = 0;
		    int length = sizeof(data) / sizeof(data[0]);
		    while (i < length - 8)
		    {
		        Player* temp = (Player*)&data[i];
		        if (temp->id == 1 && temp->level == 8)		//	结构体两个int,8个字节
		        {
		            printf("address:%x id=%d, level=%d\n", &data[i], temp->id, temp->level);
		        }
		        i++;
		    }
		}
		int main(int argc, char* argv[])
		{
		    search_Struct();
		    return 0;
		}
	void 数组指针1()
	{
		char (*px1)[2][3][2];
	    px1 = (char (*)[2][3][2])code;
	    printf("%d \n",sizeof(px1)); //始终是数组指针站字节宽度一直都是4字节
	    printf("%d \n",sizeof(*px1)); //去掉*字节宽度是1所以总宽度是1x2x3=6
	    printf("%x \n",*(*(*(*(px1+3)+2)+4)+2)); //1x2x3x2x3=36 1x3x2x2=12 1x2x4=8 1x2=2 --> 36+12+8+2=58 ==> 20
    }
    void 数组指针2()
    {
	    int (*px)[2];
	    px = (int (*)[2])code;
	    printf("%x \n",*(*(px+0)+0)); // 这里就是首元素
	    printf("%x \n",*(*(px+1)+0)); // 4x2x1=8 4x0=0 8+0=8 
	    printf("%x \n",*(*(px+2)+3));    // 4x2x2=16 4x3=12 16+12=28 
    }
*(p+i) = p[i]                    
*(*(p+i)+k) = p[i][k]                    
*(*(*(p+i)+k)+m) = p[i][k][m]                    
*(*(*(*(*(p+i)+k)+m)+w)+t) = p[i][k][m][w][t]  

17. 移位

移位图
反汇编

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值