首页
社区
课程
招聘
[原创]恶意代码分析入门系列之 - 基础知识
发表于: 2020-9-1 11:48 5856

[原创]恶意代码分析入门系列之 - 基础知识

2020-9-1 11:48
5856

0x00 前言


在第一小节完成了环境的搭建,成功搭建好了一个可用于恶意样本分析的虚拟机环境,在这小节,先介绍一些关于恶意样本的相关知识,也算是为恶意样本分析做准备。


首先,我没有写详细的汇编教程,论坛中有非常多的汇编教程,读者可以多多利用论坛的搜索功能,找到一些相关的知识点。大多数情况来说,遇到的问题之前都有人在论坛中求问过,只是措辞和询问的方式不一样,大家遇到问题的时候可以先利用论坛的搜索功能或结合google进行搜索。


为了不让之后的内容过于抽象,在本小节中介绍基础的汇编知识。



0x00 汇编基础内容

    简单来说,寄存器是CPU内部用于存放数据的小型存储区域,寄存器是内存与CPU能够交互的一个关键。

    以x86为例,常见的有8个通用寄存器。

    EAX    eax是累加器,在做加法和乘法运算的时候,eax是默认寄存器    

    EBX    ebx是基地址寄存器,通常被用于寻址    

    EXC    ecx是计数器,通常用于循环计数    

    EDX    edx通常用于存放除法运算产生的余数    

    ESI     esi是源寄存器,通常在字符串操作中使用

    EDI    edi与esi对应,edi表示目标寄存器    

    EBP    ebp是基址指针,通常用于指向栈底    

    ESP    esp是堆栈指针,与ebp对应,通常指向栈顶。

    还有一些特殊的寄存器,刚开始的时候不用掌握那么多,后面遇到再去学习就行。


    eax ebx exc edx 这四个寄存器,除了本身自带的一些功能,他们还常常被用于一些运算。开发人员可以直接使用一些汇编指令去操作这几个寄存器实现一些简单的功能,需要注意的是,eax寄存器还有一个存放函数返回值的功能。在大多数情况下,一个函数调用完成之后,返回值都会保存在EAX寄存器中


    后面的esi和edi通常会配合数据段寄存器DS来使用,通常情况下,我们不会动esi和edi的值。


    esp和ebp分别用于指向栈顶和栈底,是两个特别关键的寄存器。esp和ebp涉及到操作系统中一个最基础的概念"堆栈"。


    

    说是堆栈,其实是指栈,当我们描述堆的时候都会直接说堆。

    栈的原理其实很简单,从C语言的角度来看,栈是一种数据结构,先入后出。从计算机系统来看,栈是一个具有先入后出属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。可以说我们所见到的函数调用,基本上都是跟栈挂钩的。
    在一个函数开头,经常可以看到如下的语句来开辟新的堆栈:

    push ebp

    mov ebp,esp

  esp 40h


    这里首先保存当前的ebp,然后通过mov将ebp和esp指向同一个位置,再通过sub指令更改esp的指向,这样就为当前函数开辟出了一个新的栈空间。

    sub esp 40h里面的40h,是编译器预留给当前函数的空间大小。


    

     然后在函数结尾,通常会使用

    作为返回,退出当前函数。


    在汇编代码中,ebp常见的有两种使用方式,分别是:

    ebp + xx

    ebp - xx

    根据windows内存空间的生长方向我们可以知道,ebp + xx 是取参数的值,ebp -xx 是取局部变量的值。

    有时候也会使用esp的加减来定位变量,但是这种情况比较少见。

    

    

    举个

    我们在对一个函数调用的时候,就会将一些关键信息入栈。

    最开始入栈的是函数的参数,在C语言中,函数的参数入栈顺序是自右向左依次入栈。

    最后入栈的是函数的返回地址,这个地址很重要,关系着函数执行完成之后该回到哪里继续执行。

    比如我有个函数fun1(int a, char b, int c )

    我在main函数中调用了fun1函数,

    那么参数入栈的时候

    最先入栈的是变量c

    其次入栈的是变量b

    接着入栈的是变量a

    最后入栈的是main函数调用这个fun1函数之后的地址


    

    汇编指令相关

    

    先介绍几个常见的指令:

    mov

    add

    sub

    push

    pop

    call

    rete


    最常见的汇编指令是mov,mov指令有两个操作数,格式如下:

    

    mov指令的功能是将操作数2的内容移动到操作数1,这里的操作数1必须是寄存器,操作数2可以是地址、常量、寄存器。例如:

    mov eax,31 是把0x31赋值给eaxmov eax,ebx 是把ebx的值赋值给eax

    那么可不可以用 mov 0x00401000,31 来表示将0x31放入到0x00401000这个地址呢,答案是不行的。

    因为如果第一个操作数变成了地址,编译器并不能保证这个地址一定存在,而数据是从内存中读入到CPU中的,要让CPU能够正常操作,所以其中一个操作数必须为寄存器。


    

    add和sub是一组运算指令,分别对应加减运算。

    这两个指令和mov类似,使用方法都是

    add  操作数1,操作数2sub  操作数1,操作数2功能是将操作数1和操作数2进行add或者sub操作,然后结果保存在操作数1的位置所以很明显,操作数1也必须是一个寄存器。比如

    add eax,0x10是将eax中的值和0x10相加,然后结果保存在eax中add eax,ebx 是将eax中的值和exb相加然后保存在eax中。sub指令也是同理。比如我要利用eax进行运算可以这样写:



    还有一组常用的汇编指令是push和pop

    和之前的汇编指令不同,push和pop只有一个操作数。

    比如

    push eax

    push ebx

    push 0x10

    pop edi

    pop ebx

    pop bex

    ......


    push指令的功能是将跟在push指令后的操作数入栈。

    当一条push指令执行之后,ebp的值不变,esp的值会减去入栈类型的长度。

    比如假设当前的栈如下:


    



栈底ebp指向的地址是0x0012FF80

栈顶esp指向的地址是0x0012FF70

现在执行push 0x10,那么堆栈的变化如下


与之对应的,pop指令执行之后,ebp还是不变,esp的值加上pop出的类型的长度。

关于汇编的这部分,笔者去年写了一点点在公众号上,有兴趣的读者可以看看https://mp.weixin.qq.com/s/8ZdX7cOLp18FMtE5vBgTkA

由于图片转过来不清晰,又有水印,这里就不继续讲汇编了,讲点后面的内容。



主要分为

PE文件(Windows平台可执行文件,如exe和dll文件)

ELF文件(Linux平台下的可执行文件)
office文档文件(注意2007版本是个分界点,07版本之前的文档文件本质是二进制文件,之后本质是压缩包)

ps1文件(powershell脚本)


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-9-1 12:00 被jux1a编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 622
活跃值: (1231)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
态度不错,可以多看下别人的分析报告
2020-9-1 11:59
0
雪    币: 10361
活跃值: (4560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
支持一下。另外,最懂微软的还是微软,如果上不了Google,为啥不用必应国际版搜一下呢,切记切到国际版
2020-9-1 12:51
0
游客
登录 | 注册 方可回帖
返回
//