免杀笔记 ----->汇编基础

免杀的第一件事,当然是学汇编啦,小编也是从0开始呢!!!一起来看看吧!

免责声明,本人所有教学内容仅供参考,无任何不良引导,内容资料来自网络,如有侵权请联系删除!!!!                       

1.数据宽度

学计算机的大家一定不会陌生,比如经常听什么一个字节等于8个比特 ....这种之类的。  

其实可以分为以下这些单位

  • 比特 比如像我们平时所看见的那些 0101101001010这样子,一位就是一个bit
  • 字节 也可以叫做Byte,就好像我们上面说的,一个字节就是8个比特
  • 字   是计算机进行数据存储和数据处理的运算的单位。而一个字又是两个字节

这里就要说一下,如果你往一个32位寄存器里面存很大的数,肯定是不行的,超过了数据宽度

2.进制

我们在生活中用的最多的就是十进制了 ,但是计算机可不是用的十进制 而是二进制01010这些

其中我们在免杀中需要熟悉的,就是2进制和十进制吧,8进制的话少一点

就比如  0x08 =   8   = 0100    ,    0x10 = 16 =  10000    0xC = 12  =   1100

这种简单的计算还是要会

3.通用寄存器

我们一开始先是去研究32位下的寄存器

  • EAX
  • ECX
  • EDX
  • EBX
  • ESP
  • EBP

我们去OD看一下mimikatz的就知道了 ,这个OD只能打开32位的哦,你别拿64位的mimikatz 那当然是打不开的

我们看见最右边那个就是对应的通用的寄存器  

4.OD的使用

虽然在这里插入感觉有的点突兀,但是既然提到了OD,那还是要给大家去讲一下怎么使用的

  • F8 单步步过   

当我们想要从0075ECF7走到0075ECFA的时候只需要F8 一下就好了!!!

  • F7 单步步入 

就拿我们的c++来举例子

当我们输出完1之后我们就要进入函数,如果f8的话就直接略过函数,f7则是单步进入

那这个举例子,如果我们继续f8的话,就会直接执行这个函数的结果,然后走到0075ED0E

如果我们F7的话,就会进入到栈(可以看见前面的地址都不一样了)

  • F2 打断点   

假如我现在有一个程序在 0075EF12这个位置我想让他跑去 0075EF27这个位置

我们只需要在 0075EF27 这个位置点一下,然后直接F2

他变红了,但是此时我们程序还是运行到了0075EF27这个位置而已

  • F4 运行到指定位置

继续上面,我们只要F4一下,就能让他跑到0075EF27这个位置

5.汇编指令

1.mov 

其实就是move,我来操作一遍你就懂了

这个指令就是将334的值移动到eax这个寄存器里面

   看,瞬间就变红了  其中eax就是寄存器,然后0x334我们称之为立即数

当然了,除了我们直接这样子赋值,也可以直接这么写

意思就是把Dword(32位数据类型)ptr 在 0x00BF5F9D4这个地址的值给拿出来,丢到EAX里面

不出什么以外的话,EAX应该是变成了00B5F9E8

当然,也是可以直接把寄存器当作一个地址来用的,但这时候寄存器的值就变成了一个地址,而不是寄存器的值  我们后买你lea会讲到

2.add  sub

这个看起来都很明白了吧,我就直接用一个示例来演示一下得了

这个意思就是EAX=EAX+0x11 有没有编成里面的+=的意思捏,嘻嘻嘻

不出意外就是 00CFFC55

   那么同理 SUB也是一样的!!! 我就不过多演示了

3.and or xor

这个可能对于学过离散数学的会比较好理解,我们还是来举一个例子

     4 and 7  也就是离散数学上的 4 和取7 (二进制)

  • 4:0100
  • 7:0111                                   这两个合取结果应该是  0100 也就是4

结果也是如此

   

然后就是我们的XOR   也就是异或      为我们还是拿上面的来举例子

  • 4:0100
  • 7:0111            这两个异或结果应该是    0011  (异或就是只有01同时存在才为1)

那么答案不出意外的话,应该就是 3

4.lea

这个用的多,最简单的就是这样

将0x446这个地址(不是这个地址的数)直接给到EAX,所以EAX应该会变成446

但是一般没人会这么用,我们更多的是直接用的寄存器

至于为什么要这样子用,我们讲到堆栈的时候你就懂了

最常用的更是我们的立即数配和寄存器

至于为什么,我们后面再说

5.push pop

这两个都是涉及到了堆栈,我们下面再讲

6.cmp

这个我们也放在下面讲

5.内存寻址

这个其实我们在上面的add的时候就已经提到了一些了

其实也就是通过内存地址来获取或者得到一些值,这个内存地址,你可以直接写地址,或者直接写寄存器。

不过还是要说一下,我们刚才的那个 dword ptr ds:[0x2121312]这个例子

我们里面提到的ds  ,在用户层只是起寻址的作用,在内核层涉及到段,页有别的作用

cs :代码段
ds :数据段
ss :堆栈段
es :附加段

6.代码是怎么执行的

我们一定用过VS或者devcpp等其他编译器写过代码,那么他的底层逻辑是什么呢???

因为我们的CPU只能看的懂0 1 ,所以一般是这样的一个过程

c/cpp代码  ---> 汇编代码 ------> 硬编码 ------> CPU

 我们去VS看一下,就像这段最简单的hello world

我们右键转到反汇编

就能看见我们的汇编代码

然后我们再把他转换成硬编码

然后就是到了CPU那里了,我们的 "Hello World!" 就是这么被执行的

7.标志寄存器

我们再OD里面除了能看见我们的通用寄存器,我们还能看见这个标志寄存器

对于32位下,我们的标志寄存器叫做EFlag ,也就是我们看见上面的EFL

在64位下,我们的标志寄存器就叫做RFlag 

其中EFlag寄存器各个位置有各个位置的不同作用,特别是ZF这个位置,也就是上面我们看见的Z这个位置,我们来举个栗子

我们用CMP这个汇编指令的时候,我们总不能把返回结果存储在eax中吧,这时候就要用到标志寄存器中的ZF这一个位置

   我们能看见Z这个位置变成了1  就是说明了结果相同,这个到后面的JCC语句会用

同样的还有CF

CF:进位标志CF(Carry Flag),如果运算结果的最高位产生了一个进位或借位,其值为1,否则为0

OF

如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。

8.堆栈

栈Stack,堆Heap  这两个对于程序员来说更是经典

:用于存储函数的局部变量和函数调用的上下文信息。栈上的数据在函数执行结束时自动释放。

这个其实很好理解,就像这个代码,我们的两个a都是开在了栈上面

:用于动态分配的内存,由程序员手动分配和释放。在C语言中,使用 malloc()calloc() 等函数分配的内存位于堆上。

这个也很好理解,像下图,就是在堆区上开辟了一个长度为三的整数数组,并且用p指向了首地址

 而规定了,进出函数的前后堆栈的地址不能改变

Jmp

这个其实就是Jump的缩写,就是直接跳转到其他地址

我们之际JMP一下,就能直接跳到我们对应的地方了

但是JMP不会堆堆栈的位置进行改变,怎么看是否改变呢???   还记得我们之前的通用寄存器码

  • ESP   指向栈顶
  • EBP   指向栈底

我们可以去尝试,堆栈在JMP下是不会发生改变的

Call Ret

这两个一般都是搭配使用的

  • Call 跳转到指定地址并返回到当前指令的下一行,当我们调用这个的时候,他会先将esp提升四个字节,并将返回地址压入堆栈   (提栈)
  • ret   返回到指定地址,当我们调用这个指令的时候,会将esp降低四个字节,并且从堆栈中取出返回地址,传递给EIP(运行的地址)

这么说似乎有点抽象,我们来举个栗子就懂了

首先我们遇到了一个call,然后有以下的信息

  • 当前的地址是    EF12    下一步的地址是  EF17
  • 当前的EBP是    FB34         ESP的地址是FB28

然后我们单步F7进入一下

然后又能收集到以下的信息

  • 我们的ESP减少了4(提栈)ESP变成了FB24
  • 并且我们的返回地址EF17被压栈,压入了FB24

然后我们直接跑到retn那里

可以看见函数跑了一通之后我们的ESP还是FB24里面还是EF17,然后我们F8走一下

还是能收集到以下的信息

  • retn成功的返回了我们的地址 
  •  ESP是FB28  EBP是FB34    和函数一开始调用时候的栈地址是一样的!!!!!

Push Pop

这两个其实和Call 和Ret有点像的,但是也有差异

在介绍这两个命令之前,还得讲一下栈的数据存储,是从高到低的,比如我上一个是94,那么我压栈存数据之后就应该存在90这个地址!

Push 压栈,将ESP减少4,然后将数据压入。

有点类似call的功能,只是将返回的地址更换成了数据

Pop 出栈 将ESP加4,并且将原来ESP的数值取出放到指定的地址或者寄存器

有了上面的Push的基础,我们就不难理解我们的pop了,直接举例子吧

像这样,就是直接把ESP的值取出来,mov到EAX,然后将ESP的值加上4

9.JCC语句

JCC不知道能不能被翻译为Jump Condition Code 

其实就是和标志寄存器实现了一个联动,一般格式如下

JCC target_address
JZ/JE     jump if zero;jump if equal      其实就是检查ZF这个位是不是为1,是则跳转
举个栗子,首先我们构造一个Z标志位为1的一种情况
然后我们直接构造一个JCC语句
因为我们的Z位置是1,所以他是会直接跳到我们对应的位置的
JNZ/JNE         jump if not zero;jump if  not equal     如果ZF为0则跳转
这个其实和上面的那个差不多,我就不给大家演示了。

10.堆栈图

这个算是有点难吧,不过也是理解就好了,其实你把上面的指令都理解清除的话,就不会有问题。

我们之前说的栈平衡其实有点问题,就是并不是说call回来之后esp一定会与原来相同,有些则是通过 add esp,0x...... 这样来实现ESP不变    ------->这样我们也叫他是栈平衡(看他是在函数外平衡堆栈还是在函数内平衡堆栈)


具体堆栈图就不演示了,因为会非常麻烦,而且混乱(除非视频讲解),但是原理还是一样

  • 25
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值