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


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

    一丶LOOP指令(循环指令)

    作用:

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

    例如:

      

    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的原理是什么?

      首先先看一段汇编程序

    jmp PROC_ADD           ;跳转到函数执行
    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 带有参数的传递

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

    看代码:

      

    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带参数

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

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

    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的详细调用

    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

  • 相关阅读:
    linux 还能这么来
    JS还能这么来
    FFmpeg常用命令
    golang gin框架默认打印日志写入到文件 (http请求打印写入到文件而不是控制台)
    社保、新农合介绍以及报销比例介绍
    Lightroom 快捷键集合
    golang map基础使用-初始化
    SOLID
    java dump
    Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
  • 原文地址:https://www.cnblogs.com/iBinary/p/7487839.html
Copyright © 2020-2023  润新知