16位汇编第九讲汇编指令以及逆向中的花指令

2018-01-05 17:44:10 浏览数 (1)

                                      16位汇编第九讲汇编指令以及逆向中的花指令

一丶LOOP指令(循环指令)

作用:

  循环指令利用cx计数器自动减1,方便实现计数循环的程序结构

例如:

代码语言:javascript复制
mov cx,3   
loop1:    ;标号
        .....
    LOOP loop1;不断的循环标号,然后cx-- 直到变为零

每次循环过后,cx都会自减,直到cx == 0,不过现在的loop指令不常用了,因为局限性太大,比如loop只能自减,而不能自增,所以我们都用 JCC 指令,来模拟loop指令

二丶子程序指令(函数的概念基于子程序指令)

问题? 什么是子程序

  1.子程序是完成特定功能的一段程序

  2.当主程序(调用程序)需要执行这个功能的时候,采用call调用指令转移到改子程序的起始处执行

  3.当运行万子程序的功能的时候,采用 ret 返回指令回到主程序继续执行

如果懂C语言或者别的更高级的语言的请看

  这个其实就是函数,为了代码的重用性,可利用性研究出来的,否则汇编代码一多就会很乱,比如有效的管理代码

比如ret指令,其实就是平衡栈的,在C语言中变成了语法,为return了

1.最原始的Call

主程序调用子程序的流程示意图:

这里主要介绍call传参,以及使用ret

Call的原理是什么?

  首先先看一段汇编程序

代码语言:javascript复制
jmp PROC_ADD           ;跳转到函数执行
代码语言:javascript复制
d_One: jmp END_EXIT   ;跳转到程序结束位置,结束程序 PROC_ADD:             ;函数ADD方法   mov ax,1   mov bx,1   add ax,bx            ;ax和bx相加,结果保存到ax中,ax当做返回值返回   jmp d_ONE            ;跳转到  函数执行后的吓一吓一跳指令继续执行END_EXIT:             ;程序结束的代码不关注  mov ax,  4c00h int 21h

看到上面的代码发现了什么,是不是和我们上面的图很像

主程序 -> 子程序的add方法, 然后 -> 跳转回来,跳转到下一条指令继续指令

这个就是雏形了,但是你有没有想过,这个add只能实现1 1 了,根本就不通用,怎么办,而且如果调用多次怎么办,

一直加标号,一直调用吗,显然是不切实际的.

2.Call 带有参数的传递

上面发现了一个大缺陷,就是不能参数传递,这样就不行了,那么我们要想办法,可不可以在外面传入参数

看代码:

代码语言:javascript复制
mov cx,1
mov dx,1
jmp PROC_ADD           ;跳转到函数执行
d_One: jmp END_EXIT   ;跳转到程序结束位置,结束程序 

PROC_ADD:             ;函数ADD方法
   mov ax,cx            ;改为cx  
   mov bx,dx            ;改为dx
   add ax,bx            ;ax和bx相加,结果保存到ax中,ax当做返回值返回
   jmp d_ONE            ;跳转到  函数执行后的吓一吓一跳指令继续执行

END_EXIT:             ;程序结束的代码不关注
  mov ax,
  4c00h int 21h    

我们发现,在外部寄存器更改了,就可以修改参数了,但是还有问题,寄存器一共才多少个,当我们参数有10个怎么办

比如CreateProcess API,它的参数就有10个以上,不用关心API是干啥的,可以看下参数.

正好10个,我们的寄存器都不够用了怎么办

3.更高级的Call带参数

  我们这个时候就会想到,寄存器已经不能满足我们的需求,这个时候,可以使用栈,我们可以使用栈来保存信息

出栈的时候栈平衡(就是使栈空间不被破坏)一下

代码语言:javascript复制
mov cx,2
    push cx             ;压栈
    mov dx,1
    push dx        ;调用函数
    CALL PROC_ADD    
    mov dl,al
    mov ah,2h       ;执行显示al内容
    int 21h
    jmp END_EXIT
PROC_ADD:
    mov bp,sp
    mov ax,[bp  2]      ; 从栈中取出内容,注意为什么 2
    mov bx,[bp  4]
    add ax,bx
    ret

在这里应该注意到了,我们用Call调用的时候,为什么函数内部要 2

原因是当这个子程序执行完毕的时候,需要返回到主程序执行,所以主程序的下一条指令已经压栈了,所以 2位置,可以取得参数

最后调用ret平栈

当程序遇到ret的时候,做的事情

1. 首先修改IP的值,IP的值, =  (ss栈段寄存器) * 16 (sp栈顶)的值,

2.(sp栈顶) = (sp栈顶) 2

需要注意的是,ret只会把最后压入的返回地址返回,但是参数还没有平栈,只能在调用完毕之后,在返回地址出的下一条指令自己平栈

4.Call的详细调用

代码语言:javascript复制
mov cx,1
push cx
mov bx,2
push bx
CALL PROC_ADD

PROC_ADD:
    ......
    ret

ret的作用,就是从栈栈中取出返回地址,然后赋值给IP继续执行吓一条指令

但是注意,这里并没有平栈,我们必须在外面自己平栈

比如,我们我们入栈两个参数,比如  add sp,4   让sp平栈

四丶花指令

 请看下面的汇编代码

我们发现jmp的地方下面申请了一个字节,但是在汇编的时候,这1个字节和mov的机器码在一起了

因而产生的汇编代码就出错了,花指令混淆就是这样,这段代码还是可以正常执行的

对抗手法

1.如果是动态的调试,那么花指令是没用的(动态调试就是一步一步走)为什么,因为为了保证汇编代码不出错

每走一次代码都会重新反汇编

2.花指令主要对抗的是静态调试,因为病毒是不能运行的,只能看二进制和汇编,这个时候怎么办

我们发现了,他要jmp, jmp 1个字节,这个时候可以写个工具去弄,把jmp变为NOP(就是告诉CPU不执行)

现在我们在WINHEX中找到,然后改为 90机器码(代表NOP)

修改的时候,先看下反汇编 找到01的地方,改为90则NOP掉了,那么正确的反汇编就出现了

然后发现花指令去除了,这个就是最简单的花指令,当然这个可以通过寻找jmp的跳转的字节数,把里面的内容依次修改为NOP,所以就有了花指令去除工具

注意,这里是最简单的花指令,还有更复杂的,道高一尺魔高一丈,所以没有完整的花指令去除工具,到最后,可能你需要自己去分析,自己去修改了.

 学习资料链接: http://pan.baidu.com/s/1slHi4vN 密码:hvjp

0 人点赞