整理复习汇编语言的知识点,以前在学习《Intel汇编语言程序设计 - 第五版》时没有很认真的整理笔记,主要因为当时是以学习理解为目的没有整理的很详细,这次是我第三次阅读此书,每一次阅读都会有新的收获,这次复习,我想把书中的重点,再一次做一个归纳与总结(注:16位汇编部分跳过),并且继续尝试写一些有趣的案例,这些案例中所涉及的指令都是逆向中的重点,一些不重要的我就直接省略了,一来提高自己,二来分享知识,转载请加出处,敲代码备注挺难受的。

这次复习的重点就是高级语言,各种语句的底层实现逻辑,我们手工的来实现一些常用的表达式,逐级递增难度,本文中所仿写的汇编流程,风格,参考自VS2013编译器的Debug实现,由于不是研究编译特性的文章,故此处不考虑编译器对代码实施的各种优化措施,只注重C语言代码的汇编化。

IF/AND/OR 语句

IF中的AND语句的构造: and语句为等式两边只要一边返回假,则整个等式就不需要继续下去了,只有等式1成立的情况下才会继续判断等式2是否成立。

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20;int var2 = 10;int var3 = 50;if (var1 >= 20 and var2 <= 100 and var3 == 50){printf("xor eax,eax");}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50flag DWORD ?
.codemain PROC; if(var1 >= 20 and var2 <= 100 and var3 == 50)cmp dword ptr ds:[var1],20     ; 判断是否大于20jl L1                          ; 不大于则跳转cmp dword ptr ds:[var2],100    ; 判断是否小于100jg L1                          ; 不小于则跳转cmp dword ptr ds:[var3],50     ; 判断是否等于50jne L1                         ; 不等于则跳转mov dword ptr ds:[flag],1      ; 说明等式成立 flag=1jmp L2L1:    mov dword ptr ds:[flag],0L2:    cmp dword ptr ds:[flag],0je lop_end                     ; 为0则跳转,不为0则继续执行xor eax,eax                    ; 此处是执行if语句内部xor ebx,ebxxor ecx,ecxjmp lop_endlop_end:nop                            ; 直接结束invoke ExitProcess,0main ENDP
END main

IF中OR语句的构造: OR语句的判断则是只要等式两边一边的结果返回为真,则整个表达式的后半部分直接跳过。

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20;int var2 = 10;int var3 = 50;if (var1 > var2 || var2 <= var3){printf("xor eax,eax");}else if(var3 == 50 || var2 > 10){printf("xor ebx,ebx");}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROC; if (var1 > var2 || var2 <= var3)mov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]     ; var1 > var2jg L1mov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]     ; var2 <= var3jg L2                           ; 条件是 var2 > var3 则跳转L1:xor eax,eax                     ; printf("xor eax,eax")jmp lop_endL2:; else if(var3 == 50 || var2 > 10)cmp dword ptr ds:[var3],50je L3cmp dword ptr ds:[var2],10      ; var2 > 10jle lop_endL3:xor ebx,ebx                      ; printf("xor ebx,ebx")jmp lop_endlop_end:nopint 3invoke ExitProcess,0main ENDP
END main

IF中AND/OR混合构造:

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20;int var2 = 10;int var3 = 50;if ((var1 >= 10 && var2 <= 20) || (var2 == 10 && var3 >= 40)){printf("xor eax,eax");}else{printf("xor ebx,ebx");}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROC; if ((var1 >= 10 && var2 <= 20) && (var2 == 10 || var3 >= 40))cmp dword ptr ds:[var1],10     ; var1 >= 10jl L1cmp dword ptr ds:[var2],20     ; var2 <= 20jg L1cmp dword ptr ds:[var2],10     ; var2 == 10je L2cmp dword ptr ds:[var3],40     ; var3 >= 40jl L1jmp L2L1:xor ebx,ebx               ; elsejmp lop_endL2:xor eax,eax                ; printf("xor eax,eax")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

IF语句嵌套调用: 在编写这样子的嵌套语句时,应该由外到内逐层解析,这样能更容易写出优美的表达式。

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int x = 100, y = 200, z = 300;int var1 = 20,var2 = 10,var3 = 50;if (var1 >= var2){if ((x<y) && (z>y)){printf("xor eax,eax");}else{printf("xor ebx,ebx");}}else if (var2 > var3){printf("xor ecx,ecx");}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datax DWORD 100y DWORD 200z DWORD 300var1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]       ; if(var1 >= var2) ?jl L1mov eax,dword ptr ds:[x]cmp eax,dword ptr ds:[y]          ; if((x<y)) ?jge L2mov eax,dword ptr ds:[z]           ; if((z>y)) ?cmp eax,dword ptr ds:[y]jle L2xor eax,eax                        ; printf("xor eax,eax")jmp lop_endL1:mov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]jle lop_endxor ecx,ecx                      ; printf("xor ecx,ecx")jmp lop_endL2:xor ebx,ebx                      ; printf("xor ebx,ebx")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

IF 判断平年闰年: 闰年时年份对400取余等于0的数,或者对4取余等于0并且对100取余不等于0的数.

#include <windows.h>
#include <stdio.h>int main(int argc,char * argv[])
{int year = 2017;if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)){printf("%d 闰年 \n", year);}{printf("%d 平年 \n", year);}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataYear DWORD 2017szFmtR BYTE '%d 是闰年',0dh,0ah,0szFmtP BYTE '%d 是平年',0dh,0ah,0
.codemain PROCmov eax,dword ptr ds:[Year]     ; year = 2017;cdqmov ecx,400idiv ecx                        ; year % 400 == 0test edx,edxje L1mov eax,dword ptr ds:[Year]and eax,080000003h              ; year % 4test eax,eaxjne L2mov eax,dword ptr ds:[Year]cdqmov ecx,100idiv ecx                         ; year % 100 != 0test edx,edx                     ; 比较余数je L2                            ; 跳转则是平年L1:   mov eax,dword ptr ds:[Year]invoke crt_printf,addr szFmtR,eax     ; 是闰年jmp lop_endL2:    mov eax,dword ptr ds:[Year]invoke crt_printf,addr szFmtP,eax     ; 是平年jmp lop_end   lop_end:int 3   main ENDP
END main

IF语句三层嵌套:

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int x = 100, y = 200, z = 300;int var1 = 20,var2 = 10,var3 = 50;int result = 1;if ((var1 >= var2) && (var2 <= var3) || (var3 > var1)){if ((x % 2 == 0) || (y % 2 != 0)){if (result == 1)printf("xor eax,eax");}}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datax DWORD 100y DWORD 200var1 DWORD 20var2 DWORD 10var3 DWORD 50result DWORD 1
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]      ; and var1 >= var2jl lop_endmov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]      ; and var2 <= var3jle L1mov eax,dword ptr ds:[var3]cmp eax,dword ptr ds:[var1]       ; or var3 > var1jle lop_endL1:mov eax,dword ptr ds:[x]and eax,080000001h                ; eax = eax % 2 = 0jns L2                            ; eax = 0 则跳转dec eaxor eax,0fffffffeh                 ; eax = eax % 2 != 0inc eaxL2:mov eax,dword ptr ds:[result]test eax,eax                      ; if(result == 1)jne L3jmp lop_endL3:xor eax,eax                        ; printf("xor eax,eax")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

IF语句中的TEST: 这里有多种写法,第一种是比较好的写法,不需要增加太多编号,第二种是正常人的思维方式.

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int x = 100, y = 200, z = 300;int var1 = 20,var2 = 10,var3 = 50;int result = 1;if (var1 >= var2 && var2 <= var3){if (x == 100 || y == 200 || z == 300){if (result == 1)printf("xor eax,eax");}}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datax DWORD 100y DWORD 200z DWORD 300var1 DWORD 20var2 DWORD 10var3 DWORD 50result DWORD 1
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]      ; var1 >= var2jl lop_endmov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]      ; var2 <= var3jg lop_endmov eax,dword ptr ds:[x]cmp eax,100                 ; x == 100jne lop_endmov eax,dword ptr ds:[y]cmp eax,200                 ; y == 200jne lop_endmov eax,dword ptr ds:[z]cmp eax,300                 ; z = 300jne lop_endmov eax,dword ptr ds:[result]test eax,eax                 ; eax = 0 ?jz lop_endxor eax,eaxjmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

以下是人的逻辑方式.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datax DWORD 100y DWORD 200z DWORD 300var1 DWORD 20var2 DWORD 10var3 DWORD 50result DWORD 1
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]      ; var1 >= var2jge L1jmp lop_endL1:mov eax,dword ptr ds:[var2]      ; var2 <= var3cmp eax,dword ptr ds:[var3]      jle L2L2:mov eax,dword ptr ds:[x]cmp eax,100                       ; x == 100 ?je L3mov eax,dword ptr ds:[y]          ; y == 200 ?  cmp eax,200je L3mov eax,dword ptr ds:[y]cmp eax,300                       ; z == 300 ?je L3jmp lop_endL3:mov eax,dword ptr ds:[result]     ; result == 1 ?test eax,eax                      ; eax && eax != 0jz lop_endxor eax,eaxjmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

IF-ELSEIF-ELSE: 多层循环从何治,看我的,给我写。

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20,var2 = 10,var3 = 50;if (var1 > 20)printf("xor eax,eax");else if (var2 > 10)printf("xor ebx,ebx");else if (var2 < var3)printf("xor ecx,ecx");elseprintf("xor edx,edx");return 0;
}

正常写法

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,20                       ; var1 > 20jg L1mov eax,dword ptr ds:[var2]cmp eax,10                       ; var2 > 10jg L2cmp eax,dword ptr ds:[var3]jl L3                            ; var2 < var3xor edx,edx                      ; printf("xor edx,edx")jmp lop_endL1:xor eax,eax                      ; printf("xor eax,eax")jmp lop_endL2:xor ebx,ebx                      ; printf("xor ebx,ebx")jmp lop_endL3:xor ecx,ecx                      ; printf("xor ecx,ecx")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

编译器是这样干的,我把他的思路写一下。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,20jle L1xor eax,eax                ; printf("xor eax,eax")jmp lop_endL1:mov eax,dword ptr ds:[var2]cmp eax,10jle L2xor ebx,ebx                 ; printf("xor ebx,ebx")jmp lop_endL2:mov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]jge L3xor ecx,ecx                  ; printf("xor ecx,ecx") jmp lop_endL3:xor edx,edx                  ; printf("xor edx,edx")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

编译器对于if-elseif-else是这样处理的.

int var1 = 20;int var2 = 10;int var3 = 50;if (var1 > 20)printf("xor eax,eax");else if (var2 >= 20)printf("xor ebx,ebx");else if (var3 <= 20)printf("xor ecx,ecx");elseprintf("xor edx,edx");.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,20                     ; var1 > 20 ?jle L1                         ; 不大于则跳到L1继续判断xor eax,eaxjmp lop_end                    ; 最后都要跳向结束L1:    mov eax,dword ptr ds:[var2]cmp eax,20                     ; var1 >= 20 ?jl L2                          ; 不大于则继续判断L2xor ebx,ebxjmp lop_endL2:    mov eax,dword ptr ds:[var3]cmp eax,20                      ; var3 <= 20 ?jg L3                           ; 大于则跳到L3xor ecx,ecxjmp lop_endL3: xor edx,edxjmp lop_endlop_end:xor esi,esiinvoke ExitProcess,0main ENDP
END main

IF的前期脑残写法: 写的烂,没编译器生成的代码有趣,垃圾保存。
脑残1

if(var1 > var2) and (var2 < var3)
{xor eax,eax
}else if(var1 > var3)
{xor ebx,ebx
}.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]      ; if(var1 > var2)jg L1mov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var3]      ; else if(var1 > var3)jg L3L1:mov eax,dword ptr ds:[var2]      ; if(var2 < var3)cmp eax,dword ptr ds:[var3]jl L2L2:xor eax,eaxjmp lopL3:xor ebx,ebxjmp loplop:nopinvoke ExitProcess,0main ENDP
END main

脑残2

if var1 == var2
{if x > y{xchg x,y}else{x=10y=20}
}else
{var1 = 0var2 = 0
}.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datax BYTE 6y BYTE 5var1 DWORD 10var2 DWORD 10.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]     ; var1 == var2 ?jne L1                          ; 不等于跳转到L1mov al,byte ptr ds:[x]cmp al,byte ptr ds:[y]          ; x > y ?jg L2                           ; 大于跳到L2mov byte ptr ds:[x],0           ; 不大于则执行x=10 y=20mov byte ptr ds:[y],0jmp lopL1:mov dword ptr ds:[var1],0       ; var1 != var2 则执行mov dword ptr ds:[var2],0L2:mov al,byte ptr ds:[x]mov bl,byte ptr ds:[y]xchg al,bl                      ; x y 数值交换mov byte ptr ds:[x],almov byte ptr ds:[y],bljmp loplop:nopinvoke ExitProcess,0main ENDP
END main

if 双层嵌套结构: 包含有and,or运算符的连用处理.

int var1 = 20;int var2 = 10;int var3 = 50;if (var1++ > 5 && var2++ >= 10){var3 = var3 + 10;var3 << 2;if (var3 <= 100 or var3 <= 1000)xor eax,eaxelsexor ebx,ebx}.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50.codemain PROCinc dword ptr ds:[var1]           ; var1++mov eax,dword ptr ds:[var1]cmp eax,5                         ; var1 > 5 ?jg L1jmp lop_endL1:inc dword ptr ds:[var2]           ; var2++mov eax,dword ptr ds:[var2]       ; var2 >=10 ?cmp eax,10jge L2jmp lop_endL2:mov eax,dword ptr ds:[var3]       ; 获取 var3add eax,10                        ; var3 = var3 + 10shl eax,2                         ; var3 << 2cmp eax,100jle L3                            ; var3 <= 100 ?cmp eax,1000                      ; eax orjle L3                            ; var3 <= 1000 ?jmp L4                            ; elseL3:xor eax,eaxjmp lop_endL4:xor ebx,ebxjmp lop_endlop_end:nopinvoke ExitProcess,0main ENDP
END main

编译器对于此类嵌套出处理结果是这样的,由于and指令左面如果成立则继续执行右面的判断,如果不成立右面的直接掠过,这样的话就比较有趣了,如下是我根据汇编代码推测的一段片段,。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50tmp DWORD ?flag DWORD ?.codemain PROCmov eax,dword ptr ds:[var1]mov dword ptr ds:[tmp],eax       ; 将var1原值备份到tmpmov ecx,dword ptr ds:[var1]add ecx,1                        ; 递增var1并会写到变量中mov dword ptr ds:[var1],ecxcmp dword ptr ds:[tmp],5         ; 用原值与5做比较jle L1                           ; 如果 var1 < var2mov dword ptr ds:[flag],1jmp L2L1:  mov dword ptr ds:[flag],0         ; 判断的是and的第一个等式L2:    cmp dword ptr ds:[flag],0je lop_endmov eax,dword ptr ds:[var2]mov dword ptr ds:[tmp],eax        ; 备份var2mov ecx,dword ptr ds:[var2]add ecx,1                         ; 递增运算++mov dword ptr ds:[var2],ecxcmp dword ptr ds:[tmp],10         ; 判断 var2>=10 ?jl L3                             ; 不大于则跳到L3mov dword dword ptr ds:[flag],1   ; 大于则标志flag=1jmp L4L3:    mov dword ptr ds:[flag],0L4:    cmp dword ptr ds:[flag],0je lop_end                         ; 不跳转则执行内部ifmov eax,dword ptr ds:[var3]add eax,10mov dword ptr ds:[var3],eax         ; 递增var3mov eax,dword ptr ds:[var3]shl eax,2mov dword ptr ds:[var3],eax         ; var3 = var3 << 2cmp dword ptr ds:[var3],100         ; var3 <= 100jle L5cmp dword ptr ds:[var3],1000        ; var3<=1000jg L6                               ; 跳转到内层elseL5:xor eax,eaxnopjmp lop_endL6:xor ebx,ebxnopjmp lop_endlop_end:xor eax,eaxinvoke ExitProcess,0main ENDP
END main

IF中的自增自减处理: 执行自增自减运算需要找一个临时区域来存放自增后的数据,所以首先要开辟局部空间,多数情况下开辟空间可在栈上,例如使用sub esp,12来分配栈空间,并初始化后即可使用,最后需要将该空间恢复.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.codemain PROCpush ebpmov ebp,espsub esp,12                    ; 开辟 3*4 =12 的空间lea edi,dword ptr ss:[ebp-12] ; 指向栈中基址mov ecx,3                     ; 填充次数 12/4 = 3 mov eax,0cccccccch            ; 填充物rep stosd                     ; 初始化开始mov dword ptr ss:[ebp-12],1mov dword ptr ss:[ebp-8],2    ; 给每个地址赋值mov dword ptr ss:[ebp-4],3mov eax,dword ptr ss:[ebp-12] ; 取第一个数据1mov ebx,dword ptr ss:[ebp-4]  ; 取第二个数据3add eax,ebx                   ; 执行递增mov dword ptr ss:[ebp-8],eax  ; 写回栈add esp,12                     ; 平栈mov esp,ebppop ebpinvoke ExitProcess,0main ENDP
END main
#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20,var2 = 10,var3 = 50;if (var1++ >= 20 && ++var2 > 10){printf("xor eax,eax");}return 0;
}

以下代码中需要注意,当我们使用var1++时程序是将++后的结果赋值到了栈中存放,并让var1变量递增,而判断则使用的是栈中的原值,相反++var1则是在原值上直接进行操作,将操作结果赋值给原值后在进行判断.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROCpush ebpmov ebp,espsub esp,8                     ; 开辟 2*4 =8 的空间lea edi,dword ptr ss:[ebp-8]  ; 指向栈中基址mov ecx,2                     ; 填充次数 8/4 = 2mov eax,0cccccccch            ; 填充物rep stosd                     ; 初始化开始mov eax,dword ptr ds:[var1]mov dword ptr ss:[ebp-8],eax   ; 将var1存入临时变量中add eax,1mov dword ptr ds:[var1],eax    ; 将相加后的结果写回到var1cmp dword ptr ss:[ebp-8],20    ; 用原值与20对比jl L1mov dword ptr ss:[ebp-4],1     ; 局部变量存放标志=1jmp L2L1:   mov dword ptr ss:[ebp-4],0L2:   cmp dword ptr ss:[ebp-4],0je lop_endmov eax,dword ptr ds:[var2]    ; 继续执行 ++var2add eax,1mov dword ptr ds:[var2],eaxcmp dword ptr ds:[var2],10     ; var2 > 10jle lop_endxor eax,eax                    ; printf("xor eax,eax")lop_end:add esp,8                     ; 平栈mov esp,ebppop ebpinvoke ExitProcess,0main ENDP
END main

IF嵌套中的移位1:

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20,var2 = 10,var3 = 50;if (((var1 << 2) ^ (var2 << 3)) || ((var2 << 1) ^ (var3 << 3))){if ((var1 >= var2) || (var2 <= var3) && (var3 == 50)){printf("xor eax,eax");}}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROC; ((var1 << 2) ^ (var2 << 3))mov eax,dword ptr ds:[var1]shl eax,2mov ecx,dword ptr ds:[var2]shl ecx,3xor eax,ecxje L1; ((var2 << 1) ^ (var3 << 3))mov eax,dword ptr ds:[var2]shl eax,1mov eax,dword ptr ds:[var3]shl ecx,3xor eax,ecxje lop_end; (var1 >= var2)L1:    mov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]jge L2; (var2 <= var3)mov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]jg lop_endL2: ; (var3 == 50)cmp dword ptr ds:[var3],50jnz lop_endxor eax,eax               ; printf("xor eax,eax")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

第二种如果判断

#include <stdio.h>
#include <windows.h>int main(int argc,char * argv[])
{int var1 = 20,var2 = 10,var3 = 50;if (((var1 << 2) % 2) || (var3 >> 1) % 3){if (((var1 << 2) + 10) > 50){printf("xor ebx,ebx");}}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50
.codemain PROC; ((var1 << 2) % 2)mov eax,dword ptr ds:[var1]shl eax,2and eax,080000001h          ; var1 % 2jns L2                      ; 非负数则跳转; (var3 >> 1) % 3           ; 为负数执行第二个表达式L1: mov eax,dword ptr ds:[var3]sar eax,1                   ; var3 >> 1cdq                         ; 扩展为8字节mov ecx,3                   ; 除以3idiv ecxtest edx,edx                ; 比较余数是否为0je lop_end; ((var1 << 2) + 10) > 50L2: mov eax,dword ptr ds:[var1]shl eax,2add eax,10cmp eax,50jle lop_endxor eax,eax                  ; printf("xor ebx,ebx")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

IF中的三目运算符:

#include <stdio.h>
#include <Windows.h>int main(int argc,char *argv[])
{int var1 = 20, var2 = 10, var3 = 50;if ((var1 > var2 ? 1 : 0) && (var2 <= var3 ? 1 : 0)){printf("xor eax,eax");}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datavar1 DWORD 20var2 DWORD 10var3 DWORD 50flag DWORD ?
.codemain PROCmov eax,dword ptr ds:[var1]cmp eax,dword ptr ds:[var2]   ; var1 > var2 ?jle L1mov dword ptr ds:[flag],1     ; 表达式1成立jmp L2L1:  mov dword ptr ds:[flag],0L2:    cmp dword ptr ds:[flag],0je lop_endmov eax,dword ptr ds:[var2]cmp eax,dword ptr ds:[var3]   ; var2 <= var3jg L3mov dword ptr ds:[flag],1     ; 表达式2成立jmp L4L3:  mov dword ptr ds:[flag],0L4:    cmp dword ptr ds:[flag],0je lop_endxor eax,eax                   ; printf("xor eax,eax")jmp lop_endlop_end:int 3invoke ExitProcess,0main ENDP
END main

While /For 语句构建

While/FOr 循环框架: while循环,for循环的简单框架,后期会逐步提高难度,最终实现一个循环链表结构。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datacount DWORD ?.codemain PROCmov dword ptr ds:[count],0            ; 设置while初始化S1:    cmp dword ptr ds:[count],10           ; 设置最大循环数jge loop_end                          ; 判断是否循环结束xor eax,eax                           ; 执行循环体mov eax,dword ptr ds:[count]           ; 取出循环条件add eax,1                              ; 递增mov dword ptr ds:[count],eax           ; 写回jmp S1loop_end:int 3invoke ExitProcess,0main ENDP
END main

再看一下他的好基友,do-while是如何构造的,相比于while,该语句是先执行在判断,从效率上来说这个效率要高于while.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datacount DWORD ?
.codemain PROCmov dword ptr ds:[count],0     ; 初始化循环次数S1:   xor eax,eax                    ; 执行循环体mov eax,dword ptr ds:[count]   ; 取出计数器add eax,1                      ; 递增mov dword ptr ds:[count],eax   ; 回写cmp dword ptr ds:[count],10    ; 与10做对比jl S1                          ; 小于则继续循环int 3invoke ExitProcess,0main ENDP
END main

最后看一个for语句的实现流程,该语句的构建方式相对于While来说略显复杂些,效率远不及While,反汇编后发现,编译器是这样构建的.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datacount DWORD ?
.codemain PROCmov dword ptr ds:[count],0          ; 设置 int x = 0;jmp L2L1: mov eax,dword ptr ds:[count]        ; x = x++add eax,1mov dword ptr ds:[count],eaxL2:    cmp dword ptr ds:[count],10         ; 比较 x < 10jge lop_endxor eax,eax                         ; 执行循环体jmp L1lop_end:int 3invoke ExitProcess,0main ENDP
END main

在Python中for循环是for x in range(2,10)可以指定一个范围,我们接着尝试构建一下.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.lib.datastart_count DWORD ?end_count DWORD ?
.codemain PROCmov dword ptr ds:[start_count],2     ; 指定开始循环编号mov dword ptr ds:[end_count],5       ; 指定结束循环编号mov ecx,dword ptr ds:[start_count]L1:   cmp dword ptr ds:[end_count],ecxjle lop_endxor eax,eax                          ; 循环体内部add ecx,1                            ; 每次递增mov dword ptr ds:[start_count],ecxjmp L1lop_end:int 3invoke ExitProcess,0main ENDP
END main

While遍历数组: 以下案例主要通过仿写While循环结构并通过比例因子寻址,实现对一个DWORD数组的遍历.

#include <stdio.h>
#include <Windows.h>int main(int argc,char *argv[])
{int Array[10] = { 1,2,3,4,5,6,7,8,9,10 };int count = 0;while (count < sizeof(Array) / sizeof(int)){printf("value = %d \n", Array[count]);count = count + 1;}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 1,2,3,4,5,6,7,8,9,10count DWORD ?szFmt BYTE 'value = %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[count],0        ; 初始化循环mov ecx,0                         ; 设置循环计数(比例因子)S1:  cmp dword ptr ds:[count],lengthof MyArray  ; 与数组总长度对比jge lop_end                                ; 是否结束lea esi,dword ptr ds:[MyArray]             ; 获取数组基地址mov ebx,dword ptr ds:[esi + ecx * 4]       ; 比例因子寻址invoke crt_printf,addr szFmt,ebx           ; 调用系统crtmov ecx,dword ptr ds:[count]add ecx,1                                   ; 计次循环递增mov dword ptr ds:[count],ecxjmp S1lop_end:int 3invoke ExitProcess,0main ENDP
END main

For循环尝试判断: 这次使用For循环,首先仿写For循环语句,然后在内部判断指定数值是否合格,合格输出.

#include <stdio.h>
#include <Windows.h>int main(int argc,char *argv[])
{int Array[10] = { 56,78,33,45,78,90,32,44,56,67 };for (int x = 0; x < 10; x++){if (Array[x] >= 50){printf("out -> %d \n", Array[x]);}}return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 56,78,33,45,78,90,32,44,56,67count DWORD ?szFmt BYTE 'out -> %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[count],0      ; int x = 0jmp L1L2: mov eax,dword ptr ds:[count]add eax,1                       ; x ++mov dword ptr ds:[count],eaxL1:cmp dword ptr ds:[count],10     ; x < 10jge lop_endmov eax,dword ptr ds:[count]          ; 获取循环次数,当作因子lea esi,dword ptr ds:[MyArray]        ; 取数组基地址mov ebx,dword ptr ds:[esi + eax * 4]  ; 因子寻址cmp ebx,50jl L2                                 ; 如果小于50则跳转到下一次循环invoke crt_printf,addr szFmt,ebx      ; 调用系统crtjmp L2lop_end:int 3invoke ExitProcess,0main ENDP
END main

继续增加难度,求最大最小平均值的代码,尝试用汇编实现.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{int Array[10] = { 56,78,33,45,78,90,32,44,56,67 };int max_result = 0,min_result = 100,sum_result = 0,avg_result = 0;for (int x = 0; x < 10; x++){if (Array[x] >= max_result){max_result = Array[x];}if (Array[x] <= min_result){min_result = Array[x];}sum_result = sum_result + Array[x];avg_result = sum_result / 10;}printf("max = %d min = %d sum = %d avg = %d \n", max_result,min_result,sum_result,avg_result);system("pause");return 0;
}

以下这段代码,写的有点小问题,但大体完善,先思考一下哪里的问题,后期我在发答案!

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 56,78,33,45,78,90,32,44,56,67count DWORD ?max_result DWORD 0min_result DWORD 100sum_result DWORD 0avg_result DWORD 0szFmt BYTE 'max = %d min = %d sum = %d avg = %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[count],0      ; int x = 0jmp L1L2: mov eax,dword ptr ds:[count]add eax,1                       ; x ++mov dword ptr ds:[count],eaxL1:cmp dword ptr ds:[count],10     ; x < 10jge lop_endmov eax,dword ptr ds:[count]lea esi,dword ptr ds:[MyArray]mov ebx,dword ptr ds:[esi + eax * 4]cmp ebx,dword ptr ds:[max_result]      ; Array[x] >= max_resultjl L3mov dword ptr ds:[max_result],ebx      ; max_result = Array[x];L3:mov ebx,dword ptr ds:[esi + eax * 4]cmp ebx,dword ptr ds:[min_result]      ; Array[x] <= min_resultjg L4L4:mov ebx,dword ptr ds:[esi + eax * 4]mov edx,dword ptr ds:[sum_result]      ; sum_result + Array[x];add ebx,edxmov dword ptr ds:[sum_result],ebx      ; sum_resultmov eax,dword ptr ds:[sum_result]cdqmov ecx,10idiv ecx                               ; sum_result / 10;mov dword ptr ds:[sum_result],eax      ; avg_resultjmp L2lop_end:mov eax,dword ptr ds:[max_result]mov ebx,dword ptr ds:[min_result]mov ecx,dword ptr ds:[sum_result]mov edx,dword ptr ds:[avg_result]invoke crt_printf,addr szFmt,eax,ebx,ecx,edxint 3invoke ExitProcess,0main ENDP
END main

问题显而易见,相信大家都看出来了,我就直接公布正确代码了

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 56,78,33,45,78,90,32,44,56,67count DWORD ?max_result DWORD 0min_result DWORD 100sum_result DWORD 0avg_result DWORD 0szFmt BYTE 'max = %d min= %d sum= %d avg = %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[count],0      ; int x = 0jmp L1L2: mov eax,dword ptr ds:[count]add eax,1                       ; x ++mov dword ptr ds:[count],eaxL1:cmp dword ptr ds:[count],10     ; x < 10jge lop_endmov eax,dword ptr ds:[count]lea esi,dword ptr ds:[MyArray]mov ebx,dword ptr ds:[esi + eax * 4]cmp ebx,dword ptr ds:[max_result]      ; Array[x] >= max_resultjl L3mov dword ptr ds:[max_result],ebx      ; max_result = Array[x];L3:mov ebx,dword ptr ds:[esi + eax * 4]cmp ebx,dword ptr ds:[min_result]      ; Array[x] <= min_resultjg L4mov dword ptr ds:[min_result],ebxL4:mov ebx,dword ptr ds:[esi + eax * 4]   ; Array[x]add dword ptr ds:[sum_result],ebx      ; sum_result = sum_result + Array[x];mov eax,dword ptr ds:[sum_result]cdq                                    ; 符号扩展mov ecx,10                             ; / 10idiv ecx                               ; sum_result / 10;mov dword ptr ds:[avg_result],eax      ; avg_resultjmp L2lop_end:mov eax,dword ptr ds:[max_result]mov ebx,dword ptr ds:[min_result]mov ecx,dword ptr ds:[sum_result]mov edx,dword ptr ds:[avg_result]invoke crt_printf,addr szFmt,eax,ebx,ecx,edxint 3main ENDP
END main

Do-While 与跳出循环: 要说continue与break语句的唯一区别,就在于一个是跳转到了本次循环的结束位置,另一个则是条向了总循环结束位置.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{int Array[10] = { 56,78,33,45,78,90,32,15,56,67 };int index = 0;do{if (Array[index] > 10 && Array[index + 1] <= 20){printf("array[1] => %d array[2] => %d \n", Array[index], Array[index + 1]);break;}index = index + 1;} while (index < 10);return 0;
}
.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 56,78,33,45,78,90,32,15,56,67count DWORD ?szFmt BYTE 'array[1] => %d array[2] => %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[count],0               ; int index = 0;L1:mov eax,dword ptr ds:[count]cmp dword ptr ds:[MyArray + eax * 4],10  ; Array[index] > 10jle L2mov eax,dword ptr ds:[count]add eax,1cmp dword ptr ds:[MyArray + eax * 4],20  ; Array[index + 1] <= 20jg L2mov esi,dword ptr ds:[MyArray + eax * 4 - 4]   ; esi = Array[index]mov edi,dword ptr ds:[MyArray + eax * 4]       ; edi = Array[index+1]invoke crt_printf,addr szFmt,esi,edijmp lop_end                                    ; breakL2:    mov eax,dword ptr ds:[count]add eax,1                                 ; index = index + 1;mov dword ptr ds:[count],eaxcmp dword ptr ds:[count],10               ; index < 10jl L1lop_end:                                          ; breakint 3main ENDP
END main

For循环多重IF判断: 在循环中我们首先判断两个数组中元素是否大于0,大于则执行加法运算,然后输出基数或偶数.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{int SrcArray[10] = { 56,78,33,45,78,90,32,15,56,67 };int DstArray[10] = { 59,77,89,23,11,45,67,88,93,27 };int index = 0;for (index = 0; index < 10; index++){if (SrcArray[index] != 0 && DstArray[index] != 0){int sum = SrcArray[index] + DstArray[index];if (sum % 2 == 0)printf("偶数: %d \n", sum);elseprintf("基数: %d \n", sum);}}system("pause");return 0;
}

思考了一会,花费了一些时间,但还是使用汇编完成了.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataSrcArray DWORD 56,78,33,45,78,90,32,15,56,67DstArray DWORD 59,77,89,23,11,45,67,88,93,27index DWORD 0sum DWORD 0szFmt1 BYTE '基数: %d ',0dh,0ah,0szFmt2 BYTE '偶数: %d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[index],0        ; index = 0jmp L1L2:   mov eax,dword ptr ds:[index]add eax,1                         ; index++mov dword ptr ds:[index],eaxL1:cmp dword ptr ds:[index],10       ; index < 10jge lop_endmov eax,dword ptr ds:[index];cmp dword ptr ds:[SrcArray + eax * 4],0je L2                                     ; SrcArray[index] != 0mov eax,dword ptr ds:[index]cmp dword ptr ds:[DstArray + eax * 4],0   ; DstArray[index] != 0je L2; ------------------------------------------; 另类加法,通过一个SrcArray定位DstArray完成加法mov eax,dword ptr ds:[index]                 ; 获取因子lea esi,dword ptr ds:[SrcArray]              ; 取数组首地址mov ebx,dword ptr ds:[esi + eax * 4]         ; 获取 SrcArray[index]mov ecx,dword ptr ds:[esi + eax * 4 + 40]    ; 获取 DstArray[index]add ebx,ecx                                  ; SrcArray[index] + DstArray[index]mov dword ptr ds:[sum],ebx                   ; sum = SrcArray[index] + DstArray[index]mov eax,dword ptr ds:[sum]and eax,080000001h                           ; sum % 2 == 0test eax,eaxjne L3invoke crt_printf,addr szFmt2,dword ptr ds:[sum]  ; 偶数输出jmp L2L3:invoke crt_printf,addr szFmt1,dword ptr ds:[sum]  ; 基数输出jmp L2lop_end:int 3main ENDP
END main

For语句嵌套(乘法口诀表): 首先我们来接触一下For循环的嵌套实现方法,以打印99表为例,尝试使用汇编实现.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{for (int x = 1; x < 10; x++){for (int y = 1; y <= x; y++){int result = x*y;printf("%d*%d=%-3d", y, x, result);}printf("\n");}system("pause");return 0;
}

执行双层循环需要嵌套For语句,先来写一个简单的双层For循环的汇编版.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?szFmt BYTE '内层循环: %d 外层循环: %d ',0dh,0ah,0szPr  BYTE '----->',0dh,0ah,0
.codemain PROCmov dword ptr ds:[x],1        ; int x = 1jmp L1L2:   mov eax,dword ptr ds:[x]add eax,1                     ; x++mov dword ptr ds:[x],eaxL1:    cmp dword ptr ds:[x],10       ; x < 10jge lop_endmov dword ptr ds:[y],1        ; y = 1jmp L3L5: mov eax,dword ptr ds:[y]add eax,1                     ; y++mov dword ptr ds:[y],eaxL3:mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[x]      ; y <= xjg L4; 执行的是循环体内部mov eax,dword ptr ds:[x]mov ebx,dword ptr ds:[y]invoke crt_printf,addr szFmt,eax,ebxjmp L5L4:; 执行外层循环invoke crt_printf,addr szPrjmp L2lop_end:int 3main ENDP
END main

最终实现只是相应的做一个替换即可.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?szFmt BYTE '%d * %d = %d ',0szPr  BYTE ' ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[x],1        ; int x = 1jmp L1L2:   mov eax,dword ptr ds:[x]add eax,1                     ; x++mov dword ptr ds:[x],eaxL1:    cmp dword ptr ds:[x],10       ; x < 10jge lop_endmov dword ptr ds:[y],1        ; y = 1jmp L3L5: mov eax,dword ptr ds:[y]add eax,1                     ; y++mov dword ptr ds:[y],eaxL3:mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[x]      ; y <= xjg L4; 执行的是循环体内部mov eax,dword ptr ds:[x]imul eax,dword ptr ds:[y]invoke crt_printf,addr szFmt,dword ptr ds:[y],dword ptr ds:[x],eaxjmp L5L4:; 执行外层循环invoke crt_printf,addr szPrjmp L2lop_end:int 3main ENDP
END main

For简单循环(水仙花数): 所谓水仙花数是指一个三位数,其各位数字立方和等于该数本身.

例如: 153是一个水仙花数,因为153=1的三次方+5的三次方+3的三次方.
分析: 利用for循环控制100-999个数,每个数分解出个位,十位,百位.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{int x, y, z, n;for (n = 100; n < 1000; n++){x = n / 100;y = n / 10 % 10;z = n % 10;if (x * 100 + y * 10 + z == x*x*x + y*y*y + z*z*z){printf("水仙花: %-5d \n", n);}}system("pause");return 0;
}

尝试使用汇编实现计算逻辑.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?z DWORD ?n DWORD ?szFmt BYTE '水仙花: %-5d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[n],100     ; n = 100jmp L1L2:  mov eax,dword ptr ds:[n]add eax,1                    ; n++mov dword ptr ds:[n],eaxL1: mov eax,dword ptr ds:[n]cmp eax,1000                 ; n < 1000jge lop_endmov eax,dword ptr ds:[n]cdqmov ecx,100                  ; x = n / 100;idiv ecxmov dword ptr ds:[x],eaxmov eax,dword ptr ds:[n]cdqmov ecx,10idiv ecx                     ; y = n / 10;cdqmov ecx,10idiv ecx                     ; y = y % 10;mov dword ptr ds:[y],edxmov eax,dword ptr ds:[n]cdqmov ecx,10idiv ecx                     ; z = n % 10;mov dword ptr ds:[z],edx; 开始执行if()比较语句imul eax,dword ptr ds:[x],100  ; x * 100imul ecx,dword ptr ds:[y],10   ; y * 10add eax,dword ptr ds:[z]       ; + zadd ecx,eaxmov edx,dword ptr ds:[x]imul edx,dword ptr ds:[x]      ; x*x*ximul edx,dword ptr ds:[x]mov eax,dword ptr ds:[y]imul eax,dword ptr ds:[y]      ; y*y*yimul eax,dword ptr ds:[y]add edx,eaxmov eax,dword ptr ds:[z]imul eax,dword ptr ds:[z]      ; z*z*zimul eax,dword ptr ds:[z]add edx,eaxcmp ecx,edx   ; (x * 100 + y * 10 + z) == (x*x*x + y*y*y + z*z*z)jne L2mov eax,dword ptr ds:[n]invoke crt_printf,addr szFmt,eaxjmp L2lop_end:int 3    main ENDP
END main

For语句嵌套(冒泡排序): 冒泡排序实现思路从后向前,大的数下沉小的数上移,C代码如下,尝试使用汇编实现.

#include <stdio.h>
#include <Windows.h>int main(int argc, char *argv[])
{int Array[10] = { 34,78,65,77,89,43,23,55,67,8 };int x, y, temporary, ArraySize=10;for (x = 0; x < ArraySize - 1; x++){for (y = ArraySize - 1; y > x; y--){if (Array[y - 1] > Array[y]){temporary = Array[y - 1];Array[y - 1] = Array[y];Array[y] = temporary;}}}for (int x = 0; x < 10; x++){printf("%d \n", Array[x]);system("pause");return 0;
}

未完待续

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataArray DWORD 34,78,65,77,89,43,23,55,67,8x DWORD ?y DWORD ?Temporary DWORD ?ArraySize DWORD ?
.codemain PROCmov dword ptr ds:[x],0            ; x=0mov dword ptr ds:[ArraySize],10   ; ArraySize=10jmp L1L2:    mov eax,dword ptr ds:[x]add eax,1                          ; x++mov dword ptr ds:[x],eaxL1:   mov eax,dword ptr ds:[ArraySize]sub eax,1                          ; x < ArraySize - 1cmp dword ptr ds:[x],eaxjge lop_end; 内层循环体内容L4:    mov eax,dword ptr ds:[ArraySize]sub eax,1                          ; y = ArraySize - 1mov dword ptr ds:[y],eaxjmp L3mov eax,dword ptr ds:[y]sub eax,1                          ; y--mov dword ptr ds:[y],eaxL3:mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[x]            ; y > xjle L2mov ecx,dword ptr ds:[y]mov eax,dword ptr ds:[Array + ecx * 4]  ; ysub ecx,1mov ebx,dword ptr ds:[Array + ecx * 4]  ; xxchg eax,ebxmov dword ptr ds:[Array + ecx * 4],eaxadd ecx,1mov dword ptr ds:[Array + ecx * 4],ebxjmp L4jmp L2lop_end:int 3main ENDP
END main

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataArray DWORD 34,78,65,77,89,43,23,55,67,8x DWORD ?y DWORD ?Temporary DWORD ?ArraySize DWORD ?szFmt BYTE '%d --> %d ',0dh,0ah,0
.codemain PROC; 初始化的部分mov dword ptr ds:[x],0            ; x=0mov dword ptr ds:[ArraySize],10   ; ArraySize=10; 外层循环体jmp L1L2: mov eax,dword ptr ds:[x]add eax,1                          ; x++mov dword ptr ds:[x],eaxL1:   mov eax,dword ptr ds:[ArraySize]sub eax,1                          ; ArraySize - 1cmp dword ptr ds:[x],eax           ; x < ArraySizejge lop_end; 内层循环体内容mov eax,dword ptr ds:[ArraySize]sub eax,1mov dword ptr ds:[y],eaxjmp L3L4:   mov eax,dword ptr ds:[y]sub eax,1                           ; y--mov dword ptr ds:[y],eaxL3:    mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[x]jle L2mov esi,dword ptr ds:[y]mov ebx,dword ptr ds:[Array + esi * 4]         ; Array[y]mov edx,dword ptr ds:[Array + esi * 4 - 4]     ; Array[y - 1]cmp edx,ebxjle L4mov dword ptr ds:[Array + esi * 4],edxmov dword ptr ds:[Array + esi * 4 - 4],ebx; invoke crt_printf,addr szFmt,ebx,edxjmp L4jmp L2lop_end:int 3main ENDP
END main

排序完成

完整代码已经写出来了,如下所示.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataArray DWORD 34,78,65,77,89,43,23,55,67,8x DWORD ?y DWORD ?Temporary DWORD ?ArraySize DWORD ?szFmt BYTE '%d --> %d ',0dh,0ah,0
.codemain PROC; 初始化的部分mov dword ptr ds:[x],0            ; x=0mov dword ptr ds:[ArraySize],10   ; ArraySize=10; 外层循环体jmp L1L2: mov eax,dword ptr ds:[x]add eax,1                          ; x++mov dword ptr ds:[x],eaxL1:   mov eax,dword ptr ds:[ArraySize]sub eax,1                          ; ArraySize - 1cmp dword ptr ds:[x],eax           ; x < ArraySizejge lop_end; 内层循环体内容mov eax,dword ptr ds:[ArraySize]sub eax,1mov dword ptr ds:[y],eaxjmp L3L4:   mov eax,dword ptr ds:[y]sub eax,1                           ; y--mov dword ptr ds:[y],eaxL3:    mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[x]            ; Array[y - 1] > Array[y]jle L2mov esi,dword ptr ds:[y]mov ebx,dword ptr ds:[Array + esi * 4]         ; Array[y]mov edx,dword ptr ds:[Array + esi * 4 - 4]     ; Array[y - 1]cmp edx,ebxjle L4mov dword ptr ds:[Array + esi * 4],edx         ; Array[y] = Array[y - 1]mov dword ptr ds:[Array + esi * 4 - 4],ebx     ; Array[y - 1] = Array[y]; invoke crt_printf,addr szFmt,ebx,edxjmp L4jmp L2lop_end:nop; 执行打印函数mov dword ptr ds:[Temporary],0jmp L5L7: mov eax,dword ptr ds:[Temporary]add eax,1mov dword ptr ds:[Temporary],eaxL5:mov eax,dword ptr ds:[Temporary]cmp eax,10jge L6lea esi,dword ptr ds:[Array]                ; 取数组基地址mov esi,dword ptr ds:[Array + eax * 4]      ; 比例因子寻址invoke crt_printf,addr szFmt,esi,esijmp L7L6:int 3main ENDP
END main

先看排序部分

接着是输出部分

While 三层嵌套: 在写三层嵌套时,你需要注意了,在内层循环时需要清空变量,不然会导致循环一次整个程序结束掉了,就像下面的这种写法,乍一看没啥问题,可是一旦运行就会发现,程序每次都只运行外层一次循环就意外终止了,经过反汇编调试发现,是粗心导致没有让内层循环及时的置空。

#include <windows.h>
#include <stdio.h>int main(int argc,char * argv[])
{int x=1, y=1, z=1;while (x < 5){while (y < 5){while (z < 5){z = z + 1;}y = y + 1;}x = x + 1;}return 0;
}

来一个案例看看,使用三层嵌套完成案例,有1,2,3,4个数字,能组成多少个互补相同且不重复的三位数,尝试使用汇编实现以下这个逻辑。

#include <windows.h>
#include <stdio.h>int main(int argc,char * argv[])
{int x=1, y=1, z=1;while (x < 5){while (y < 5){while (z < 5){if (x != z && x != y && y != z){printf("%d,%d,%d \n", x, y, z);}z = z + 1;}z = 1;y = y + 1;}y = 1;x = x + 1;}return 0;
}

首先我们先来构建一个双层循环,然后再构建三层的.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?szFmt BYTE '外层循环: %d ---> 内层循环:%d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[x],1           ; x = 1; 外层循环L1:    mov ecx,dword ptr ds:[x]cmp ecx,5                        ; x < 5jge lop_end; 内层循环mov dword ptr ds:[y],1           ; y = 1L2:    mov ecx,dword ptr ds:[y]         ; ecx = ycmp ecx,5                        ; y < 5jge L3; 循环过程执行mov esi,dword ptr ds:[x]mov edi,dword ptr ds:[y]invoke crt_printf,addr szFmt,esi,edimov ecx,dword ptr ds:[y]add ecx,1                        ; y = y + 1mov dword ptr ds:[y],ecxjmp L2L3: mov ecx,dword ptr ds:[x]add ecx,1                        ; x = x + 1mov dword ptr ds:[x],ecxjmp L1lop_end:int 3   main ENDP
END main

接着是构建一个三层循环体,三层循环体就像汉堡一样,前面初始化部分时面包,中间时肉,后面也是面包,放在一起,很有食欲。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?z DWORD ?szFmt BYTE '外层循环: %d ---> 中间层循环: %d ---> 内层循环: %d  ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[x],1           ; x = 1; 外层循环L1:    mov ecx,dword ptr ds:[x]cmp ecx,5                        ; x < 5jge lop_end; 中间循环mov dword ptr ds:[y],1           ; y = 1L2:    mov ecx,dword ptr ds:[y]         ; ecx = ycmp ecx,5                        ; y < 5jge L3                           ; 大于跳到最外层; 内层循环mov dword ptr ds:[z],1           ; z = 1L5:  mov ecx,dword ptr ds:[z]cmp ecx,5                        ; z < 5jge L4                           ; 大于跳到中间层; 三层循环框架mov eax,dword ptr ds:[x]mov ebx,dword ptr ds:[y]mov ecx,dword ptr ds:[z]invoke crt_printf,addr szFmt,eax,ebx,ecxmov ecx,dword ptr ds:[z]add ecx,1                         ; z = z + 1mov dword ptr ds:[z],ecxjmp L5L4:   mov ecx,dword ptr ds:[y]add ecx,1                        ; y = y + 1mov dword ptr ds:[y],ecxjmp L2L3: mov ecx,dword ptr ds:[x]add ecx,1                        ; x = x + 1mov dword ptr ds:[x],ecxjmp L1lop_end:int 3   main ENDP
END main

中间的IF语句,就是汉堡包的佐料部分,肉质丝滑,入口即化,实在是美妙至极,如下时肉质部分。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.datax DWORD ?y DWORD ?z DWORD ?szFmt BYTE '%d,%d,%d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[x],1           ; x = 1; 外层循环L1:    mov ecx,dword ptr ds:[x]cmp ecx,5                        ; x < 5jge lop_end; 中间循环mov dword ptr ds:[y],1           ; y = 1L2:    mov ecx,dword ptr ds:[y]         ; ecx = ycmp ecx,5                        ; y < 5jge L3                           ; 大于跳到最外层; 内层循环mov dword ptr ds:[z],1           ; z = 1L5:  mov ecx,dword ptr ds:[z]cmp ecx,5                        ; z < 5jge L4                           ; 大于跳到中间层; 三层循环框架;mov eax,dword ptr ds:[x];mov ebx,dword ptr ds:[y];mov ecx,dword ptr ds:[z];invoke crt_printf,addr szFmt,eax,ebx,ecx; 开始在框架中搞事情mov eax,dword ptr ds:[x]cmp eax,dword ptr ds:[z]je L6mov eax,dword ptr ds:[x]cmp eax,dword ptr ds:[y]je L6mov eax,dword ptr ds:[y]cmp eax,dword ptr ds:[z]je L6invoke crt_printf,addr szFmt,dword ptr ds:[x],dword ptr ds:[y],dword ptr ds:[z]L6:   mov ecx,dword ptr ds:[z]add ecx,1                         ; z = z + 1mov dword ptr ds:[z],ecxjmp L5L4:    mov ecx,dword ptr ds:[y]add ecx,1                        ; y = y + 1mov dword ptr ds:[y],ecxjmp L2L3: mov ecx,dword ptr ds:[x]add ecx,1                        ; x = x + 1mov dword ptr ds:[x],ecxjmp L1lop_end:int 3   main ENDP
END main

Switch与循环: Switch语句与IF语句类似,不同之处就在于Switch是将跳转地址保存在数组中,需要时去数组中通过比例因子寻找到指定的内存然后,使用一条Jmp指令跳转过去,实在美妙!

先给大家看一下,我是怎吗保存这些地址的吧,汇编代码如下所示,直接取出标号,放入数组中,也可以使用堆栈存储,随意。

.386p.model flat,stdcalloption casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMemArray DWORD ?szFmt BYTE '%d,%d,%d ',0dh,0ah,0
.codemain PROCmov dword ptr ds:[MemArray],offset lop_end  mov dword ptr ds:[MemArray+4],offset L2lop_end:int 3 L2:xor eax,eaxxor ebx,ebxmain ENDP
END main

尝试构建Switch语句。

#include <windows.h>
#include <stdio.h>int main(int argc, char * argv[])
{int x = 0;while (x < 6){switch (x){case 0:printf("1"); break;case 1:printf("2"); break;case 2:printf("3"); break;case 3:printf("4"); break;case 4:printf("5"); break;default:printf("0"); break;}x = x + 1;}return 0;
}

理解了Switch的查表法,然后再配合汇编中的语法规范就可以巧妙地构造出Switch结构.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMemArray DWORD 0,0,0,0,0,0,0,0,0,0Count DWORD ?szFmt BYTE '%d ',0dh,0ah,0
.codemain PROC; 将指定标号的地址取出,并复制到数组mov dword ptr ds:[MemArray],offset S0mov dword ptr ds:[MemArray + 4],offset S1mov dword ptr ds:[MemArray + 8],offset S2mov dword ptr ds:[MemArray + 12],offset S3mov dword ptr ds:[MemArray + 16],offset S4mov dword ptr ds:[MemArray + 20],offset S_ENDmov dword ptr ds:[Count],0L1: mov ecx,dword ptr ds:[Count]cmp ecx,6jg lop_end; 通过循环次数寻找指令地址并跳转mov ecx,dword ptr ds:[Count]cmp ecx,6jg S_ENDjmp dword ptr ds:[MemArray + ecx * 4]S0:  mov eax,1invoke crt_printf,addr szFmt,eaxjmp L2S1:  mov eax,2invoke crt_printf,addr szFmt,eaxjmp L2S2:  mov eax,3invoke crt_printf,addr szFmt,eaxjmp L2S3:  mov eax,4invoke crt_printf,addr szFmt,eaxjmp L2S4:  mov eax,5invoke crt_printf,addr szFmt,eaxjmp L2S_END:   mov eax,0invoke crt_printf,addr szFmt,eaxjmp L2L2:  mov ecx,dword ptr ds:[Count]add ecx,1                        ; ecx ++mov dword ptr ds:[Count],ecxjmp L1lop_end:int 3  main ENDP
END main

Loop实现排序: 如果不自己构建排序循环,使用loop实现,则冒泡排序将变得香。

先来看一个汇编案例,我想说,观察下面的代码,你说 这是不是一个死循环呢?思考一下。

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataCount DWORD 10
.codemain PROCmov ecx,dword ptr ds:[Count]dec ecxL1:    push ecxinvoke crt_printf,addr szFmt,ecxpop ecx loop L1main ENDP
END main

不是,loop人家执行的时候,会自动的将ecx中的值减去1,所以他不是死循环,来实现一下这个需求。

#include <windows.h>
#include <stdio.h>int main(int argc, char *argv[])
{int Array[10] = { 56,88,34,67,98,25,67,10,87,43 };int x=10, y, temporary;while (x - 1 > 0){y = x;while (y > 0){if (Array[y] > Array[y - 1]){temporary = Array[y - 1];Array[y - 1] = Array[y];Array[y] = temporary;}y--;}x--;}for (int x = 0; x < 10; x++)printf("%d ", Array[x]);return 0;
}

然后使用loop实现双层夹心汉堡,口感同样一级棒.

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 25,74,89,33,24,67,93,15,78,92Count DWORD 10PrCount DWORD ?szFmt BYTE '%d ',0dh,0ah,0.codemain PROC; 数组排序mov ecx,dword ptr ds:[Count]      ; 获取到数组元素数dec ecx                           ; 数组减1L1:   push ecx                          ; 入栈保存lea esi,dword ptr ds:[MyArray]    ; 得到数组基地址L2:  mov eax,dword ptr ds:[esi]cmp eax,dword ptr ds:[esi + 4]    ; 比较第一个数组与第二个jg L3xchg eax,[esi + 4]                ; 交换数据mov [esi],eaxL3:    add esi,4loop L2pop ecx                           ; 弹出数据loop L1; for循环输出元素mov dword ptr ds:[PrCount],0jmp LL1mov ecx,dword ptr ds:[PrCount]add ecx,1mov dword ptr ds:[PrCount],ecxLL1:mov ecx,dword ptr ds:[PrCount]cmp ecx,10jg lop_endlea eax,dword ptr ds:[MyArray]mov ebx,dword ptr ds:[eax + ecx * 4]invoke crt_printf,addr szFmt,ebxmov ecx,dword ptr ds:[PrCount]add ecx,1mov dword ptr ds:[PrCount],ecxjmp LL1lop_end:int 3main ENDP
END main

While 实现(二分法): 二分查找法也是常用查找结构,主要思想是对半分,如果中位数大于则说明元素在前半部分,如果小于则说明在后半部分,该排序唯一需要注意的是,数组必须是一个有序集合.

#include <windows.h>
#include <stdio.h>int BinSearch(int value[], const int searchVal, int Count)
{int first = 0;int last = Count - 1;while (first <= last){int mid = (last + first) / 2;      // 取中位数if (value[mid] < searchVal)        // 中位数小于searchVal{                                  // 说明元素在后面first = mid + 1;}else if (value[mid] > searchVal){                                  // 否则说明元素在前last = mid - 1;}else{ // 找到后返回中位数return mid;}}return -1;
}int main(int argc, char *argv[])
{// 二分查找法,必须针对的是有序数组int Array[10] = { 1,2,3,4,5,6,7,8,9,10 };// 查找数组Array中索引7所在的下标int ret = BinSearch(Array, 7, 10);printf("数组下标: %d \n", ret);system("pause");return 0;
}

接着是尝试使用汇编实现这个查找逻辑,完整版代码已经写好了

.386p.model flat,stdcalloption casemap:noneinclude windows.inc
include kernel32.inc
includelib kernel32.libinclude msvcrt.inc
includelib msvcrt.lib.dataMyArray DWORD 1,2,3,4,5,6,7,8,9,10SearchVal DWORD 7Count DWORD 10first DWORD ?last DWORD ?mid DWORD ?szFmt BYTE '%d ',0dh,0ah,0.codemain PROCmov dword ptr ds:[first],0         ; first = 0;mov edi,dword ptr ds:[SearchVal]   ; 得到要查找的数lea ebx,dword ptr ds:[MyArray]     ; 得到数组基地址; int last = Count - 1;mov eax,dword ptr ds:[Count]sub eax,1mov dword ptr ds:[last],eax; while(first <=last)L1:   mov ecx,dword ptr ds:[first]cmp ecx,dword ptr ds:[last]jg lop_end; int mid = (last + first) / 2;mov eax,dword ptr ds:[last]add eax,dword ptr ds:[first]shr eax,1mov dword ptr ds:[mid],eax; edx = value[mid]mov esi,dword ptr ds:[mid]shl esi,2mov edx,[ebx + esi];invoke crt_printf,addr szFmt,edx; if(edx < SearchVal(edi))cmp edx,edijge L2; first = mid + 1;mov eax,dword ptr ds:[mid]add eax,1mov dword ptr ds:[first],eaxjmp L1L2:; else if (value[mid] > searchVal)cmp edx,edijle L3; last = mid - 1;mov eax,dword ptr ds:[mid]sub eax,1mov dword ptr ds:[last],eaxjmp L1L3:    ; elsemov eax,dword ptr ds:[mid]invoke crt_printf,addr szFmt,eaxjmp lop_endjmp L1lop_end:mov eax,-1int 3main ENDP
END main

Win32汇编:各种语句的构造方式相关推荐

  1. win32汇编实现拼接SQL语句

    字符串合并,在汇编语言,一般是用loop循环和cx寄存器,自己编程实现: 如果是win32汇编,可以使用movsb指令: 一般开发应用程序都会碰到拼接SQL语句,在C#这些语言用字符串连接的加号就可以 ...

  2. Win32 汇编语句模板

    Win32 汇编语句模板 一 变量 ;句柄 hInstance dd 0 hWnd dd 0 hPen dd 0 hPend dd 0 oldPen dd 0;过程变量 hInst :DWORD hP ...

  3. win32 汇编基础概念整理

    一.关于寄存器 寄存器有EAX,EBX,ECX,EDX,EDI,ESI,ESP,EBP等,似乎IP也是寄存器,但只有在CALL/RET在中会默认使用它,其它情况很少使用到,暂时可以不用理会. EAX是 ...

  4. win32汇编基础概念

    一.关于寄存器 寄存器有EAX,EBX,ECX,EDX,EDI,ESI,ESP,EBP等,似乎IP也是寄存器,但只有在CALL/RET在中会默认使用它,其它情况很少使用到,暂时可以不用理会. EAX是 ...

  5. Win32汇编_基础

    Win32汇编_基础 包含全部段的源程序结构: .386 .model flat, stdcall Option casemap:none ;<一些include语句> .stack [堆 ...

  6. Win32汇编基本编程框架

    Win32汇编编程框架如下: .386 .model flat,stdcall option casemap:none <一些include语句> .stack [堆栈段的大小] .dat ...

  7. C指针原理(23)-win32汇编及.NET调试

    2018-12-28 20:36:07 在WINDOWS系统能用到汇编的机会不多,基本都可以用C或C++代劳,更何况现在MICROSOFT的Visual Studio 系列工具非常强大,WINDOWS ...

  8. Win32汇编学习笔记之基础篇

    基础篇 第一章 背景知识 1.1 Win32的软硬件平台 1.1.1    80x86系列处理器简史 Win32可以在多种硬件平台上运行,但使用最广泛的硬件平台是基于Intel公司80x86系列处理器 ...

  9. win32汇编 MASM03

    http://blog.fishc.com/738.html#codesyntax_5 让编程改变世界 Change the world by program 代码段 .code段是代码段,所有的指令 ...

最新文章

  1. cacti监控(3)配置cacti
  2. 基于机器学习的捡球机器人设计与实现(探索)第3篇——opencv基础知识学习(2019-02-02)
  3. 神PS!老爸把儿子的画作P成现实,看完我笑哭了
  4. 【公益】开放一台Eureka注册中心给各位Spring Cloud爱好者
  5. Unreal Engine 4 的 光和影
  6. 虹软人脸识别在 linux中so文件加载不到的问题
  7. VS2017编写C++多文件时,出现LNK2005、LNK1169报错的解决方法
  8. plsql存过声明游标_PLSQL游标使用
  9. 数据科学工程篇_AB实验原理与实践
  10. 均线颜色怎么区分_六种颜色的均线包括哪六种颜色,其代表的含义分别是什么?...
  11. 公告模块phpcms
  12. ACM Southwestern European Regional Programming Contest (SWERC) 2017 J 智商题(模m同余)
  13. Python比较文本相似度的7种方法(详细)
  14. [zz]美团点评智能支付核心交易系统的可用性实践
  15. 恕我直言!千万别随便叫一个程序员为“码农”
  16. 【detectron】对输入样本如何产生anchor
  17. TCP协议——三次握手
  18. 【学习记录】QQZone项目 part1
  19. 【五一创作】Matlab 绘制风速、风向统计玫瑰花图【优化】
  20. 几万创业做什么好_适合小投资者轻资产的创业项目_加油优惠卡

热门文章

  1. 快速理解图像处理中注意力机制的应用
  2. mysql在什么情况下会变成全局查询_Linux下MYSQL数据语言,全局变量,查询
  3. 嵌入式数据库之SQLite 3
  4. 犹抱琵琶半遮面--MIMO信道中隐藏的秘密
  5. ajax异步获取数据后动态向表格中添加数据的页面
  6. 计算机开机长鸣报警,电脑开机报警,教您电脑开机一直长鸣报警怎么办
  7. 访问中国知网样式丢失
  8. java用监听捕捉点_使用Robot类创建自己的Java版屏幕捕捉程序
  9. datastage 函数_DataStage(ETL)技术总结 — 介绍篇 | 学步园
  10. vs中readfile的作用,readFile和readFileSync之间的区别