zoukankan      html  css  js  c++  java
  • 【黑客免杀攻防】读书笔记11

    0x1 加法与减法的优化原理

    1.1 加法的识别与优化

    加法优化有3种方案:

    1)形式1:变量与变量

    2)形式2:变量加常量

    3)形式3:变量加1

    C源代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	int nNum, nA = 8;
    	nNum = argc + nA;      // 形式1:变量减变量
    	printf("%d
    ",nNum);
    	nNum = argc + 9;       // 形式2:变量减常量
    	printf("%d
    ",nNum);
    	nNum = nNum + 1;       // 形式3:变量减1
    	printf("%d
    ",nNum);
    
    	return 0;
    }
    
    

    Debug反汇编:

    01297710 55            push ebp
    01297711 8BEC          mov ebp,esp
    01297713 81EC D8000000 sub esp,0xD8
    01297719 53            push ebx
    0129771A 56            push esi                   ;  9-34.<ModuleEntryPoint>
    0129771B 57            push edi
    0129771C 8DBD 28FFFFFF lea edi,[local.54]
    01297722 B9 36000000   mov ecx,0x36
    01297727 B8 CCCCCCCC   mov eax,0xCCCCCCCC
    0129772C F3:AB         rep stos dword ptr es:[edi]
    0129772E C745 EC 08000 mov [local.5],0x8          ;  nA = 8
    01297735 8B45 08       mov eax,[arg.1]            ;  eax = argc 赋值
    01297738 0345 EC       add eax,[local.5]          ;  eax = eax + nA;形式1:nNum = agrc + nA
    0129773B 8945 F8       mov [local.2],eax          ;  nNum = eax
    0129773E 8B45 F8       mov eax,[local.2]          ;  eax = nNum
    01297741 50            push eax
    01297742 68 508E3201   push 9-34.01328E50         ;  %d
    
    01297747 E8 C8C5FFFF   call 9-34.01293D14         ;  printf
    0129774C 83C4 08       add esp,0x8                ;  堆栈平衡
    0129774F 8B45 08       mov eax,[arg.1]            ;  eax = argc
    01297752 83C0 09       add eax,0x9                ;  eax = eax + 9;argc + 9;形式2:nNum = argc + 9
    01297755 8945 F8       mov [local.2],eax          ;  nNum = eax
    01297758 8B45 F8       mov eax,[local.2]          ;  eax = nNum
    0129775B 50            push eax
    0129775C 68 508E3201   push 9-34.01328E50         ;  %d
    
    01297761 E8 AEC5FFFF   call 9-34.01293D14         ;  printf
    01297766 83C4 08       add esp,0x8
    01297769 8B45 F8       mov eax,[local.2]          ;  eax = nNum
    0129776C 83C0 01       add eax,0x1                ;  eax = eax + 1;形式3:nNum = nNum+1
    0129776F 8945 F8       mov [local.2],eax          ;  nNum = eax
    01297772 8B45 F8       mov eax,[local.2]          ;  eax = nNum
    01297775 50            push eax
    01297776 68 508E3201   push 9-34.01328E50         ;  %d
    
    0129777B E8 94C5FFFF   call 9-34.01293D14         ;  printf
    01297780 83C4 08       add esp,0x8
    01297783 33C0          xor eax,eax
    01297785 5F            pop edi                    ;  9-34.<ModuleEntryPoint>
    01297786 5E            pop esi                    ;  9-34.<ModuleEntryPoint>
    01297787 5B            pop ebx                    ;  9-34.<ModuleEntryPoint>
    01297788 81C4 D8000000 add esp,0xD8
    0129778E 3BEC          cmp ebp,esp
    01297790 E8 94ABFFFF   call 9-34.01292329
    01297795 8BE5          mov esp,ebp
    01297797 5D            pop ebp                    ;  9-34.<ModuleEntryPoint>
    01297798 C3            retn
    
    

    Release反汇编:

    00EB1260 push ebp
    00EB1261 mov ebp,esp
    00EB1263 push esi
    00EB1264 mov esi,[arg.1]                                              ;  esi = argc
    00EB1267 lea eax,dword ptr ds:[esi+0x8]                               ;  eax = argc+nA;形式1:变量+变量;优化后的加法,精妙!
    00EB126A push eax
    00EB126B push 9-34.00EC64D8                                           ;  %d
    
    00EB1270 call 9-34.printf_initialize_sse2_sse2_from_osKeywordOncrt_st>;  printf
    00EB1275 add esi,0x9                                                  ;  esi = esi+9;argc+9;形式2:变量+常量
    00EB1278 push esi
    00EB1279 push 9-34.00EC64D8                                           ;  %d
    
    00EB127E call 9-34.printf_initialize_sse2_sse2_from_osKeywordOncrt_st>;  printf
    00EB1283 lea eax,dword ptr ds:[esi+0x1]                               ;  eax = esi + 1;nNum+1;形式3:变量+1;直接用esi进行地址的存储
    00EB1286 push eax
    00EB1287 push 9-34.00EC64D8                                           ;  %d
    
    00EB128C call 9-34.printf_initialize_sse2_sse2_from_osKeywordOncrt_st>
    00EB1291 add esp,0x18
    00EB1294 xor eax,eax
    00EB1296 pop esi                                                      ;  9-34.__argc_log10_table_tk_exit_tableate
    00EB1297 pop ebp                                                      ;  9-34.__argc_log10_table_tk_exit_tableate
    00EB1298 retn
              
    

    小结:

    1)变量+变量 = lea Reg32,[变量+变量]

    2)变量+常量 = add 变量+常量

    3)变量+1 = lea Reg32,[变量+1]

    注:这里的代码我和书里不一样,书中是【变量+1 = inc 常量】

    1.2 减法的识别与优化

    减法优化与加法大同小异。
    C源代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	int nNum, nA = 8;
    	nNum = argc - nA;      // 形式1:变量减变量
    	printf("%d
    ",nNum);
    	nNum = argc - 9;       // 形式2:变量减常量
    	printf("%d
    ",nNum);
    	nNum = nNum - 1;       // 形式3:变量减1
    	printf("%d
    ",nNum);
    
    	return 0;
    }
    

    Debug反汇编:

    00E07710 push ebp
    00E07711 mov ebp,esp
    00E07713 sub esp,0xD8
    00E07719 push ebx
    00E0771A push esi                   ;  9-34.<ModuleEntryPoint>
    00E0771B push edi                   ;  9-34.<ModuleEntryPoint>
    00E0771C lea edi,[local.54]
    00E07722 mov ecx,0x36
    00E07727 mov eax,0xCCCCCCCC
    00E0772C rep stos dword ptr es:[edi]
    00E0772E>mov [local.5],0x8          ;  nA = 8
    00E07735 mov eax,[arg.1]            ;  eax = argc
    00E07738 sub eax,[local.5]          ;  eax = eax - nA; eax = argc-nA;形式1:变量-变量
    00E0773B mov [local.2],eax          ;  nNum = eax
    00E0773E mov eax,[local.2]          ;  kernel32.BaseThreadInitThunk
    00E07741 push eax
    00E07742 push 9-34.00E98E50         ;  %d
    
    00E07747 call 9-34.00E03D14         ;  printf
    00E0774C add esp,0x8                ;  调用者堆栈平衡
    00E0774F mov eax,[arg.1]            ;  eax = argc
    00E07752 sub eax,0x9                ;  eax = eax - 9;argc-9;形式2:变量-常量
    00E07755 mov [local.2],eax          ;  nNum = eax
    00E07758 mov eax,[local.2]          ;  kernel32.BaseThreadInitThunk
    00E0775B push eax
    00E0775C push 9-34.00E98E50         ;  %d
    
    00E07761 call 9-34.00E03D14         ;  printf
    00E07766 add esp,0x8
    00E07769 mov eax,[local.2]          ;  eax = nNum
    00E0776C sub eax,0x1                ;  eax = eax - 1;nNum=nNum-1;形式3:变量-1
    00E0776F mov [local.2],eax          ;  nNum = eax
    00E07772 mov eax,[local.2]          ;  kernel32.BaseThreadInitThunk
    00E07775 push eax
    00E07776 push 9-34.00E98E50         ;  %d
    
    00E0777B call 9-34.00E03D14         ;  printf
    00E07780 add esp,0x8
    00E07783 xor eax,eax
    00E07785 pop edi                    ;  kernel32.74EE38F4
    00E07786 pop esi                    ;  kernel32.74EE38F4
    00E07787 pop ebx                    ;  kernel32.74EE38F4
    00E07788 add esp,0xD8
    00E0778E cmp ebp,esp
    00E07790 call 9-34.00E02329
    00E07795 mov esp,ebp
    00E07797 pop ebp                    ;  kernel32.74EE38F4
    00E07798 retn
    
    

    Release反汇编:

    012A1260 push ebp
    012A1261 mov ebp,esp
    012A1263 push esi                      ;9-34.<ModuleEntryPoint>
    012A1264 mov esi,[arg.1]               ;esi = nA
    012A1267 lea eax,dword ptr ds:[esi-0x8];esi-8;nA-8;形式1:变量-变量
    012A126A push eax
    012A126B push 9-34.012B64D8            ;%d
    
    012A1270 call 9-34.printf>;  printf
    012A1275 add esi,-0x9                  ;esi = esi-9;argc-9;形式2:变量-常量;-0x9是补码
    012A1278 push esi                      ;9-34.<ModuleEntryPoint>
    012A1279 push 9-34.012B64D8            ;%d
    
    012A127E call 9-34.printf>
    012A1283 lea eax,dword ptr ds:[esi-0x1];eax = esi-1;nNum-1;形式3:变量-1
    012A1286 push eax
    012A1287 push 9-34.012B64D8            ;%d
    
    012A128C call 9-34.printf>
    012A1291 add esp,0x18
    012A1294 xor eax,eax
    012A1296 pop esi                       ;kernel32.74EE38F4
    012A1297 pop ebp                       ;kernel32.74EE38F4
    012A1298 retn
    

    小结:

    1)变量-变量 = lea Reg32,[变量-变量]

    2)变量-常量 = add 变量+补码(常量)

    3)变量-1 = lea Reg32,[变量-1]

    注:这里的代码我和书里不一样,书中是【dec 变量】

    0x2 乘法与除法的优化原理

    左右移位就相当于在做乘除计算,左移1位相当于乘以2,右移1位相当于除以2。

    2.1 乘法

    2.1.1 乘法的位移优化

    当乘数为2的整数次方、且大于8时,编译器才会使用优化。
    c源代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	int nNum = 16;
    	printf("%p",nNum*argc);
    
    	return 0;
    }
    
    

    Debug汇编

    008D7710 push ebp
    008D7711 mov ebp,esp
    008D7713 sub esp,0xCC
    008D7719 push ebx
    008D771A push esi                   ;  9-35.<ModuleEntryPoint>
    008D771B push edi                   ;  9-35.<ModuleEntryPoint>
    008D771C lea edi,[local.51]
    008D7722 mov ecx,0x33
    008D7727 mov eax,0xCCCCCCCC
    008D772C rep stos dword ptr es:[edi]
    008D772E mov [local.2],0x10         ;  局部变量nNum = 10;0x10等于十进制16
    008D7735 mov eax,[local.2]          ;  eax = 局部变量nNum
    008D7738 imul eax,[arg.1]           ;  eax = eax*argc;乘法运算
    008D773C push eax
    008D773D push 9-35.00968E50         ;  %p
    008D7742 call 9-35.008D3D14         ;  printf
    008D7747 add esp,0x8
    008D774A xor eax,eax
    008D774C pop edi                    ;  kernel32.74EE38F4
    008D774D pop esi                    ;  kernel32.74EE38F4
    008D774E pop ebx                    ;  kernel32.74EE38F4
    008D774F add esp,0xCC
    008D7755 cmp ebp,esp
    008D7757 call 9-35.008D2329
    008D775C mov esp,ebp
    008D775E pop ebp                    ;  kernel32.74EE38F4
    008D775F retn
    

    Release汇编:

    000E1260 push ebp
    000E1261 mov ebp,esp
    000E1263 mov eax,[arg.1]
    000E1266 shl eax,0x4  ;  左移动0x4位;左移动乘以4;shl逻辑左移指令[2^4=16]
    000E1269 push eax
    000E126A push 9-35.000F64D8  ;  %p
    000E126F call 9-35.printf>
    000E1274 add esp,0x8
    000E1277 xor eax,eax
    000E1279 pop ebp     ;  kernel32.74EE38F4
    000E127A retn
    

    测试:

    1)如果结果比2的次方多1会采用加法

    2)如果结果比2的次方少1会采用减法

    2.1.2 乘法的lea指令优化

    C源代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	int a = 1, b, c, d, e, f, g;
    	b = argc+a*4+6;	// 形式1
    	c = argc+a*3+6; // 形式2
    	d = argc*2; 	// 形式3
    	e = argc*3; 	// 形式4
    	f = argc*4; 	// 形式5
    	g = argc*11; 	// 形式6
    	printf("%d %d %d %d %d %d", b, c, d, e, f, g);
    
    	return 0;
    }
    

    Debug汇编:

    00DC7710 push ebp
    00DC7711 mov ebp,esp
    00DC7713 sub esp,0x114
    00DC7719 push ebx
    00DC771A push esi                            ;  9-36.<ModuleEntryPoint>
    00DC771B push edi
    00DC771C lea edi,[local.69]
    00DC7722 mov ecx,0x45
    00DC7727 mov eax,0xCCCCCCCC
    00DC772C rep stos dword ptr es:[edi]
    00DC772E>mov [local.2],0x1                   ;  给局部变量a赋值
    00DC7735 mov eax,[local.2]                   ;  eax = a
    00DC7738 mov ecx,[arg.1]                     ;  ecx = argc
    00DC773B lea edx,dword ptr ds:[ecx+eax*4+0x6];  edx = argc+a*4+6
    00DC773F mov [local.5],edx                   ;  局部变量b = edx
    00DC7742 imul eax,[local.2],0x3              ;  先做a*3
    00DC7746 mov ecx,[arg.1]                     ;  ecx = argc
    00DC7749 lea edx,dword ptr ds:[ecx+eax+0x6]  ;  edx = 【ecx+eax+0x6】;edx = argc + (a*3) + 0x6
    00DC774D mov [local.8],edx                   ;  局部变量c = edx
    00DC7750 mov eax,[arg.1]                     ;  eax = argc
    00DC7753 shl eax,1                           ;  argc*2;左移1位,相当于乘以2
    00DC7755 mov [local.11],eax                  ;  赋值给局部变量d
    00DC7758 imul eax,[arg.1],0x3                ;  使用乘法指令;argc*3
    00DC775C mov [local.14],eax                  ;  局部变量e = eax
    00DC775F mov eax,[arg.1]                     ;  eax = argc
    00DC7762 shl eax,0x2                         ;  eax = eax*4;左移2位等于乘以4
    00DC7765 mov [local.17],eax                  ;  局部变量f = eax
    00DC7768 imul eax,[arg.1],0xB                ;  eax = argc*11;B等于十六进制的12
    00DC776C mov [local.20],eax                  ;  局部变量g = eax
    00DC776F mov eax,[local.20]
    00DC7772 push eax
    00DC7773 mov ecx,[local.17]
    00DC7776 push ecx
    00DC7777 mov edx,[local.14]
    00DC777A push edx
    00DC777B mov eax,[local.11]
    00DC777E push eax
    00DC777F mov ecx,[local.8]
    00DC7782 push ecx
    00DC7783 mov edx,[local.5]
    00DC7786 push edx
    00DC7787 push 9-36.00E58E50                  ;  %d %d %d %d %d %d
    00DC778C call 9-36.00DC3D14                  ;  printf
    00DC7791 add esp,0x1C
    00DC7794 xor eax,eax
    

    Release版反汇编代码:

    
    01271000 push ebp
    01271001 mov ebp,esp
    01271003 mov ecx,[arg.1]                 ;  exc = argc;argc=1
    01271006 imul eax,ecx,0xB                ;  g = argc*11
    01271009 push eax
    0127100A lea eax,dword ptr ds:[ecx*4]    ;  f = argc*4
    01271011 push eax
    01271012 lea eax,dword ptr ds:[ecx+ecx*2];  e = argc*3;argc=1+1*2
    01271015 push eax
    01271016 lea eax,dword ptr ds:[ecx+ecx]  ;  d = argc*2;优化成了加法 1+1
    01271019 push eax
    0127101A lea eax,dword ptr ds:[ecx+0x9]  ;  c = argc+9; 把a*3+6计算完毕;
    0127101D push eax
    0127101E lea eax,dword ptr ds:[ecx+0xA]  ;  b = argc+a*4 把a*4+6计算完毕;
    01271021 push eax
    01271022 push 9-36.01286448              ;  ASCII 25,"d %d %d %d %d %d"
    01271027 call 9-36.printf_>
    0127102C add esp,0x1C
    0127102F xor eax,eax
    01271031 pop ebp
    01271032 retn 
    
    

    2.1.3 除法与倒数相乘

    编译器世界中倒数相乘的中心思想其实就是用乘法来代替除法运算。它的原理很简单,就是将被除数乘以除数的倒数,其公式为x/y = x*(1/y),我们拿10/2作为例子,我可以得出以下推论:

    由 公式x/y = x(1/y) 可得 10/2 = 10(1/2) = 10*0.5

    这里没有写反汇编后的状态

    2.1.4 倒数相乘与定点运算的配合

    理论知识,没仔细去看

    除法

    2.1.1 除法的识别与优化

    这一章虽然讲了编译器对除法的优化,但是不做笔记。

    2.2.2 取模运算的识别与优化

    不理解,略过,需要用时回头再看

    小结

    普通除法

    mov  Reg32_1,XXXXXXXXh
    imul Reg32_2 (被除数)
    ...
    mov  Reg32_1,edx
    shr  Reg32_1,1Fh
    add  Reg32_1,edx
    

    应用计算结果(如果倒数被向上圆整了,那么根据sar指令后的数值向下圆整即可)如下:

    (除数=XXXXXXXXh*2^-32)

    除数为2的次方

    mov eax,(被除数)
    cdq
    add edx,XXh
    add eax,edx
    sar eax,YYh
    

    应用计算结果如下:

    (除数 = XXh + 1 或 2^YYh)

  • 相关阅读:
    数据库性能优化
    AutoDetectChangesEnabled及AddRange解决EF插入的性能问题
    实体框架 5 性能注意事项
    使用JS传递数组型数据回服务器
    Code First配合Entity Framework Power Tools Beta 4使用
    HighChart 体验之旅 (后台传递JSON参数和数据的方法)
    System.Transactions事务超时设置
    ASP.NET站点部署相关
    js 字符串转化成数字
    发布.net 4.0的站点到IIS7.5下时无法访问
  • 原文地址:https://www.cnblogs.com/17bdw/p/7765782.html
Copyright © 2011-2022 走看看