扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:看雪 来源:看雪 2008年10月16日
关键字: 加密解密
在本页阅读全文(共2页)
二、 直接标志转移(8位寻址)
指令格式 |
机器码 |
测试条件 |
如...则转移 |
指令格式 |
机器码 |
测试条件 |
如...则转移 | |
JC |
72 |
C=1 |
有进位 |
JNS |
79 |
S=0 |
正号 | |
JNC |
73 |
C=0 |
无进位 |
JO |
70 |
O=1 |
有溢出 | |
JZ/JE |
74 |
Z=1 |
零/等于 |
JNO |
71 |
O=0 |
无溢出 | |
JNZ/JNE |
75 |
Z=0 |
不为零/不等于 |
JP/JPE |
7A |
P=1 |
奇偶位为偶 | |
JS |
78 |
S=1 |
负号 |
JNP/IPO |
7B |
P=0 |
奇偶位为奇 |
三、间接标志转移(8位寻址)
指令格式 |
机器码 |
测试格式 |
如...则转移 |
JA/JNBE(比较无符号数) |
77 |
C或Z=0 |
> 高于/不低于或等于 |
JAE/JNB(比较无符号数) |
73 |
C=0 |
>= 高于或等于/不低于 |
JB/JNAE(比较无符号数) |
72 |
C=1 |
< 低于/不高于或等于 |
JBE/JNA(比较无符号数) |
76 |
C或Z=1 |
<= 低于或等于/不高于 |
JG/JNLE(比较带符号数) |
7F |
(S异或O)或Z=0 |
> 大于/不小于或等于 |
JGE/JNL(比较带符号数) |
7D |
S异或O=0 |
>= 大于或等于/不小于 |
JL/JNGE(比较带符号数) |
7C |
S异或O=1 |
< 小于/不大于或等于 |
JLE/JNG(比较带符号数) |
7E |
(S异或O)或Z=1 |
<= 小于或等于/不大于 |
四、无条件转移指令(fisheep译 fisheep@sohu.com)
操作码 | 伪码指令 | 含义 |
EB cb |
JMP rel8 | 相对短跳转(8位),使rel8处的代码位下一条指令 |
E9 cw |
JMP rel16 | 相对跳转(16位),使rel16处的代码位下一条指令 |
FF /4 |
JMP r/m16 | 绝对跳转(16位),下一指令地址在r/m16中给出 |
FF /4 |
JMP r/m32 | 绝对跳转(32位),下一指令地址在r/m32中给出 |
EA cb |
JMP ptr16:16 | 远距离绝对跳转, 下一指令地址在操作数中 |
EA cb |
JMP ptr16:32 | 远距离绝对跳转, 下一指令地址在操作数中 |
FF /5 |
JMP m16:16 | 远距离绝对跳转, 下一指令地址在内存m16:16中 |
FF /5 |
JMP m16:32 | 远距离绝对跳转, 下一指令地址在内存m16:32中 |
五、16位/32位寻址方式(fisheep译 fisheep@sohu.com)
操作码 |
伪码指令 |
跳转含义 |
跳转类型 |
跳转的条件(标志位) | |
0F 87 cw/cd |
JA rel16/32 |
大于 |
near |
(CF=0 and ZF=0) | |
0F 83 cw/cd |
JAE rel16/32 |
大于等于 |
near |
(CF=0) | |
0F 82 cw/cd |
JB rel16/32 |
小于 |
near |
(CF=1) | |
0F 86 cw/cd |
JBE rel16/32 |
小于等于 |
near |
(CF=1 or ZF=1) | |
0F 82 cw/cd |
JC rel16/32 |
进位 |
near |
(CF=1) | |
0F 84 cw/cd |
JE rel16/32 |
等于 |
near |
(ZF=1) | |
0F 84 cw/cd |
JZ rel16/32 |
为0 |
near |
(ZF=1) | |
0F 8F cw/cd |
JG rel16/32 |
大于 |
near |
(ZF=0 and SF=OF) | |
0F 8D cw/cd |
JGE rel16/32 |
大于等于 |
near |
(SF=OF) | |
0F 8C cw/cd |
JL rel16/32 |
小于 |
near |
(SF<>OF) | |
0F 8E cw/cd |
JLE rel16/32 |
小于等于 |
near |
(ZF=1 or SF<>OF) | |
0F 86 cw/cd |
JNA rel16/32 |
不大于 |
near |
(CF=1 or ZF=1) | |
0F 82 cw/cd |
JNAE rel16/32 |
不大于等于 |
near |
(CF=1) | |
0F 83 cw/cd |
JNB rel16/32 |
不小于 |
near |
(CF=0) | |
0F 87 cw/cd |
JNBE rel16/32 |
不小于等于 |
near |
(CF=0 and ZF=0) | |
0F 83 cw/cd |
JNC rel16/32 |
不进位 |
near |
(CF=0) | |
0F 85 cw/cd |
JNE rel16/32 |
不等于 |
near |
(ZF=0) | |
0F 8E cw/cd |
JNG rel16/32 |
不大于 |
near |
(ZF=1 or SF<>OF) | |
0F 8C cw/cd |
JNGE rel16/32 |
不大于等于 |
near |
(SF<>OF) | |
0F 8D cw/cd |
JNL rel16/32 |
不小于 |
near |
(SF=OF) | |
0F 8F cw/cd |
JNLE rel16/32 |
不小于等于 |
near |
(ZF=0 and SF=OF) | |
0F 81 cw/cd |
JNO rel16/32 |
未溢出 |
near |
(OF=0) | |
0F 8B cw/cd |
JNP rel16/32 |
不是偶数 |
near |
(PF=0) | |
0F 89 cw/cd |
JNS rel16/32 |
非负数 |
near |
(SF=0) | |
0F 85 cw/cd |
JNZ rel16/32 |
非零(不等于) |
near |
(ZF=0) | |
0F 80 cw/cd |
JO rel16/32 |
溢出 |
near |
(OF=1) | |
0F 8A cw/cd |
JP rel16/32 |
偶数 |
near |
(PF=1) | |
0F 8A cw/cd |
JPE rel16/32 |
偶数 |
near |
(PF=1) | |
0F 8B cw/cd |
JPO rel16/32 |
奇数 |
near |
(PF=0) | |
0F 88 cw/cd |
JS rel16/32 |
负数 |
near |
(SF=1) | |
0F 84 cw/cd |
JZ rel16/32 |
为零(等于) |
near |
(ZF=1) |
注:一些指令操作数的含义说明:
rel8 表示 8 位相对地址
rel16 表示 16 位相对地址
rel16/32 表示 16或32 位相对地址
第四节 浮点指令
对下面的指令先做一些说明:
st(i):代表浮点寄存器,所说的出栈、入栈操作都是对st(i)的影响
src,dst,dest,op等都是指指令的操作数,src表示源操作数,dst/dest表示目的操作数
mem8,mem16,mem32,mem64,mem80等表示是内存操作数,后面的数值表示该操作数的内存位数(8位为一字节)
x <- y 表示将y的值放入x,例st(0) <- st(0) - st(1)表示将st(0)-st(1)的值放入浮点寄存器st(0)
1. 数据传递和对常量的操作指令
指令格式 指令含义 执行的操作
FLD src 装入实数到 st(0) st(0) <- src (mem32/mem64/mem80)
FILD src 装入整数到 st(0) st(0) <- src (mem16/mem32/mem64)
FBLD src 装入 BCD 数到 st(0) st(0) <- src (mem80)
FLDZ 将 0.0 装入 st(0) st(0) <- 0.0
FLD1 将 1.0 装入 st(0) st(0) <- 1.0
FLDPI 将 pi 装入 st(0) st(0) <- ?(ie, pi)
FLDL2T 将 log2(10) 装入 st(0) st(0) <- log2(10)
FLDL2E 将 log2(e) 装入 st(0) st(0) <- log2(e)
FLDLG2 将 log10(2) 装入 st(0) st(0) <- log10(2)
FLDLN2 将 loge(2) 装入 st(0) st(0) <- loge(2)
FST dest 保存实数 st(0) 到 dest dest <- st(0) (mem32/mem64)
FSTP dest dest <- st(0) (mem32/mem64/mem80) ;然后再执行一次出栈操作
FIST dest 将 st(0) 以整数保存到 dest dest <- st(0) (mem32/mem64)
FISTP dest dest <- st(0) (mem16/mem32/mem64) ;然后再执行一次出栈操作
FBST dest 将 st(0) 以 BCD 保存到 dest dest <- st(0) (mem80)
FBSTP dest dest <- st(0) (mem80) ;然后再执行一次出栈操作
2.比较指令
指令格式 指令含义 执行的操作
FCOM 实数比较 将标志位设置为 st(0) - st(1) 的结果标志位
FCOM op 实数比较 将标志位设置为 st(0) - op (mem32/mem64) 的结果标志位
FICOM op 和整数比较 将 Flags 值设置为 st(0)-op 的结果 op (mem16/mem32)
FICOMP op 和整数比较 将 st(0) 和 op 比较 op(mem16/mem32) 后;再执行一次出栈操作
FTST 零检测 将 st(0) 和 0.0 比较
FUCOM st(i) 比较 st(0) 和 st(i) [486]
FUCOMP st(i) 比较 st(0) 和 st(i) ,并且执行一次出栈操作
FUCOMPP st(i) 比较 st(0) 和 st(i) ,并且执行两次出栈操作
FXAM Examine: Eyeball st(0) (set condition codes)
3.运算指令
指令格式 指令含义 执行的操作
加法
FADD 加实数 st(0) <- st(0) + st(1)
FADD src st(0) <- st(0) + src (mem32/mem64)
FADD st(i),st st(i) <- st(i) + st(0)
FADDP st(i),st st(i) <- st(i) + st(0) ;然后执行一次出栈操作
FIADD src 加上一个整数 st(0) <- st(0) + src (mem16/mem32)
减法
FSUB 减去一个实数 st(0) <- st(0) - st(1)
FSUB src st(0) <- st(0) - src (reg/mem)
FSUB st(i),st st(i) <- st(i) - st(0)
FSUBP st(i),st st(i) <- st(i) - st(0) ,然后执行一次出栈操作
FSUBR st(i),st 用一个实数来减 st(0) <- st(i) - st(0)
FSUBRP st(i),st st(0) <- st(i) - st(0) ,然后执行一次出栈操作
FISUB src 减去一个整数 st(0) <- st(0) - src (mem16/mem32)
FISUBR src 用一个整数来减 st(0) <- src - st(0) (mem16/mem32)
乘法
FMUL 乘上一个实数 st(0) <- st(0) * st(1)
FMUL st(i) st(0) <- st(0) * st(i)
FMUL st(i),st st(i) <- st(0) * st(i)
FMULP st(i),st st(i) <- st(0) * st(i) ,然后执行一次出栈操作
FIMUL src 乘上一个整数 st(0) <- st(0) * src (mem16/mem32)
除法
FDIV 除以一个实数 st(0) <- st(0) /st(1)
FDIV st(i) st(0) <- st(0) /t(i)
FDIV st(i),st st(i) <- st(0) /st(i)
FDIVP st(i),st st(i) <- st(0) /st(i) ,然后执行一次出栈操作
FIDIV src 除以一个整数 st(0) <- st(0) /src (mem16/mem32)
FDIVR st(i),st 用实数除 st(0) <- st(i) /st(0)
FDIVRP st(i),st FDIVRP st(i),st
FIDIVR src 用整数除 st(0) <- src /st(0) (mem16/mem32)
FSQRT 平方根 st(0) <- sqrt st(0)
FSCALE 2 的 st(0) 次方 st(0) <- 2 ^ st(0)
FXTRACT Extract exponent: st(0) <- exponent of st(0); and gets pushed
st(0) <-significand of st(0)
FPREM 取余数 st(0) <- st(0) MOD st(1)
FPREM1 取余数( IEEE ),同 FPREM ,但是使用 IEEE 标准 [486]
FRNDINT 取整(四舍五入) st(0) <- INT( st(0) ); depends on RC flag
FABS 求绝对值 st(0) <- ABS( st(0) ); removes sign
FCHS 改变符号位 ( 求负数) st(0) < -st(0)
F2XM1 计算 (2 ^ x)-1 st(0) <- (2 ^ st(0)) - 1
FYL2X 计算 Y * log2(X) st(0) 为 Y ; st(1) 为 X ;将 st(0) 和 st(1) 变为 st(0) * log2( st(1) ) 的值
FCOS 余弦函数 Cos st(0) <- COS( st(0) )
FPTAN 正切函数 tan st(0) <- TAN( st(0) )
FPATAN 反正切函数 arctan st(0) <- ATAN( st(0) )
FSIN 正弦函数 sin st(0) <- SIN( st(0) )
FSINCOS sincos 函数 st(0) <- SIN( st(0) ) ,并且压入 st(1)
st(0) <-COS( st(0) )
FYL2XP1 计算 Y * log2(X+1) st(0) 为 Y ; st(1) 为 X ; 将 st(0) 和 st(1) 变为 st(0) * log2( st(1)+1 ) 的值
处理器控制指令
FINIT 初始化 FPU
FSTSW AX 保存状态字的值到 AX AX <- MSW
FSTSW dest 保存状态字的值到 dest dest <- MSW (mem16)
FLDCW src 从 src 装入 FPU 的控制字 FPU CW <- src (mem16)
FSTCW dest 将 FPU 的控制字保存到 dest dest <- FPU CW
FCLEX 清除异常
FSTENV dest 保存环境到内存地址 dest 处 保存状态字、控制字、标志字和异常指针的值
FLDENV src 从内存地址 src 处装入保存的环境
FSAVE dest 保存 FPU 的状态到 dest 处 94 字节
FRSTOR src 从 src 处装入由 FSAVE 保存的 FPU 状态
FINCSTP 增加 FPU 的栈指针值 st(6) <- st(5); st(5) <- st(4),...,st(0) <- ?
FDECSTP 减少 FPU 的栈指针值 st(0) <- st(1); st(1) <- st(2),...,st(7) <- ?
FFREE st(i) 标志寄存器 st(i) 未被使用
FNOP 空操作,等同 CPU 的 nop st(0) <- st(0)
WAIT/FWAIT 同步 FPU 与 CPU :停止 CPU 的运行,直到 FPU 完成当前操作码
FXCH 交换指令,交换 st(0) 和 st(1) 的值 st(0) <- st(1)
st(1) <-st(0)
第五节 分析技术
在进行软件的破解、解密以及计算机病毒分析工作中,一个首要的问题是对软件及病毒进行分析。这些软件都是机器代码程序,对于它们分析必须使用静态或动态调试工具,分析跟踪其汇编代码。
一、从软件使用说明和操作中分析软件
欲破解一软件,首先应该先用用这软件,了解一下功能是否有限制,最好阅读一下软件的说明或手册,特别是自己所关心的关键部分的使用说明,这样也许能够找点线索。
二、静态反汇编
所谓静态分析即从反汇编出来的程序清单上分析,从提示信息入手进行分析。目前,大多数软件在设计时,都采用了人机对话方式。所谓人机对话,即在软件运行过程中,需要由用户选择的地方,软件即显示相应的提示信息,并等待用户按键选择。而在执行完某一段程序之后,便显示一串提示信息,以反映该段程序运行后的状态,是正常运行,还是出现错误,或者提示用户进行下一步工作的帮助信息。为此,如果我们对静态反汇编出来的程序清单进行阅读,可了解软件的编程思路,以便顺利破解。 常用的静态分析工具是W32DASM、IDA和HIEW等。
三、动态跟踪分析
虽然从静态上可以了解程序的思路,但是并不可能真正了解地了解软件的细节,如静态分析找不出线索,就要动态分析程序,另外,碰到压缩程序,静态分析也无能为力了,只能动态分析了。所谓动态分析是利用SOFTICE或TRW2000一步一步地单步执行软件。为什么要对软件进行动态分析呢?这主要是因为:
1、许多软件在整体上完成的功能,一般要分解成若干模块来完成,而且后一模块在执行时,往往需要使用其前一模块处理的结果,这一结果我们把它叫中间结果。如果我们只对软件本身进行静态地分析,一般是很难分析出这些中间结果的。而只有通过跟踪执行前一模块,才能看到这些结果。另外,在程序的运行过程中,往往会在某一地方出现许多分支和转移,不同的分支和转移往往需要不同的条件,而这些条件一般是由运行该分支之前的程序来产生的。如果想知道程序运行到该分支的地方时,去底走向哪一分支,不进行动态地跟踪和分析是不得而知的。
2、有许多软件在运行时,其最初执行的一段程序往往需要对该软件的后面各个模块进行一些初始始化工作,而没有依赖系统的重定位。
3、有许多加密程序为了阻止非法跟踪和阅读,对执行代码的大部分内容进行了加密变换,而只有很短的一段程序是明文。加密程序运行时,采用了逐块解密,逐块执行和方法,首先运行最初的一段明文程序,该程序在运行过程中,不仅要完成阻止跟踪的任务,而且还要负责对下一块密码进行解密。显然仅对该软件的密码部分进行反汇编,不对该软件动态跟踪分析,是根本不可能进行解密的。
由于上述原因,在对软件静态分析不行的条件下,就要进行动态分析了。哪么如何有效地进行动态跟踪分析呢?一般来说有如下几点:
1、对软件进行粗跟踪
所谓粗跟踪,即在跟踪时要大块大块地跟踪,也就是说每次遇到调用CALL指令、重复操作指令REP.循环操作LOOP指令以及中断调用INT指令等,一般不要跟踪进去,而是根据执行结果分析该段程序的功能。
2、对关键部分进行细跟踪
对软件进行了一定程度的粗跟踪之后,便可以获取软件中我们所关心的模块或程序段,这样就可以针对性地对该模块进行具体而详细地跟踪分析。一般情况下,对关键代码的跟踪可能要反复进行若干次才能读懂该程序,每次要把比较关键的中间结果或指令地址记录下来,这样会对下一次分析有很大的帮助。软件分析是一种比较复杂和艰苦的工作,上面的几点分析方法,只是提供了一种基本的分析方法。要积累软件分析的经验需要在实践中不断地探索和总结。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。