1625-5 王子昂 总结《2017年5月22日》 【连续第233天总结】
A. 加密与解密 控制语句
B. 高级语言中用IF-THEN-ELSE、SEITCH-CASE等语句来构成程序的判断流程,不仅条理清楚,并且维护性好
然而在汇编代码中则复杂得多,由cmp等指令后面跟着各类跳转指令jz,jnz等构成
识别关键跳转是软件解谜的一个重要技能
IF-THEN-ELSE
将其编译成汇编代码以后,整数用cmp指令比较,浮点数则用fcom,fcomp等比较
IF-THEN-ELSE的汇编代码形式一般为:
cmp a,b
jz/jnz xxxx
cmp指令不修改操作数,根据两个操作数的相减结果,影响处理的几个标志
实际上,许多情况下编译器都用test或or之类较短的逻辑指令来替换cmp指令
一般形式为test eax,eax
如eax为0,则其逻辑与运算结果为0,就设置ZF位为1,否则为0
eg:
#include <stdio.h>
int main(void)
{
int a,b=5;
scanf("%d", &a);
if(a==0)
a=8;
return a+b;
}
汇编代码为:
lea eax, dword ptr [esp] ;eax指向局部变量空间
push eax
push 00407030 ;指向字符串%d
call 00401030 ;C语言的scanf函数
mov eax, dword ptr [esp+8] ;将输入的字符传出
add esp,8 ;由于是__cdecl调用,函数外平衡堆栈
test eax,eax ;若eax为0则ZF置1,否则置0
jne 00401020 ;若ZF=1不跳转,否则跳转
mov eax,8
00401020 add eax,5
pop ecx ;释放局部变量用到的内存,相当于add esp,4
ret
SWITCH-CASE
该语句编译后实质上就是多个IF-THEN语句的嵌套组合,编译器会将SWITCH变异成一组不同关系运算组成的语句
编译器在编译代码的时候,可能同一段高级语言,由于优化选项不同,产生的汇编代码也会截然不同
例如可以用dec eax指令代替cmp指令,这样更短,执行更快
另外,一些编译器优化时,在不改变原逻辑的前提下,使用数学技巧把源代码中一些逻辑分支语句转换成算术操作,消除或减少程序中出现的条件转移指令,提高CPU的性能
eg:
int main(void)
{
if(FindWindow(NULL,'计算器'))
return 1;
else
return 5;
}
用VC++编译后,汇编代码为:
push 406030 ;Title="计算器"
push 0 ;Class=0
call dword ptr [405090] ;FindwWindowA
neg eax
sbb eax,eax
and al,0FC
add eax,5
retn
首先用neg指令检验eax是否为0,结果存放在CF标志位中。sbb指令将目的操作数减去原操作数,再减去借位CF,结果送到目的操作数。sbb eax,eax这局的结果由CF决定,当CF为1时,eax为-1,否则为0。
接下来根据eax的值FFFFFFFFh和0来决定最终结果。当eax是FFFFFFFFh时,计算结果是1;当eax是0时,计算结果为5
and al,0FC
add eax,5
这类代码比较常见,要知道是条件转移指令优化生成的,才有思路去还原
C. 明日计划
加密与解密 循环语句