汇编学习笔记

前言

为了更深刻的理解c/c++,学习一下汇编(注:本文汇编讲解只是为了更好的使用c/c++,并不是严格的学习汇编)

我们所有的高级语言除了解释型的,比如javascript,都是被编译器编译成二进制代码。这些二进制代码术语叫COFF文件。

COFF文件在windows平台上被叫做PE文件,linux平台上叫elf文件。

windows上的PE文件常见的有exe dll ocx sys,编译器将我们的程序编译成PE文件,这些PE文件 本质上都是二进制,就是很多01组成的,稍微合并一下就能看到汇编指令,

比如 010110011 可能对应 mov eax, 1  

因为指令数量是一定的,所以这些都是固定的

寄存器

根据冯·诺伊曼原理 计算机的的组成是这样的:cpu + 存储设备

而cpu是由运算器,控制器和寄存器组成 ,所有的指令都是在cpu里面运算的,寄存器英文单词叫register,先简单理解为就是一个存储设备。

常见寄存器有: AX BX CX DX ES DS GS SP BP IP

不常见寄存器:GT GS

寄存器简介:http://blog.csdn.net/rankun1/article/details/70880239

80386以前的cpu,也就是16位操作系统下,所有的寄存器都是16位的,等到了32位时代大多数的寄存器被intel扩展成32位的了,也就是4个字节 32位

注意是大多数,不是所有。比如AX变成EAX,BX变EBX, CX变ECX,DX变EDX,  E是extend,扩展的意思。

所以,一个EAX的低16位是AX,AX低8位是AL,高八位是AH。EAX高16位没有名字,因为一般要么用低16位,要么用32位 ,没有单独用高16位。就像数字12(十二)一样,没有低位2,高位1没有意思。

到64位系统再次做了一个扩展,变成RAX RBX RCX RDX,这里不在多说。

EAX

EAX一般有一个很重要的用途,存储函数返回值!(这是编译器的建议规则,大多数编译器会遵循,但也有的不遵循,详情学习编译原理)

比如你调用一个函数,返回一个值,等函数调用完了 栈内存被销毁了,你去哪里找这个返回值呢?

比如这条语句:

int i = func();

假如func()返回一个值,实际上在函数销毁前 

mov eax, 函数返回值

这样函数调用完了再从eax中将返回值取出来给i,也就是

 mov ptr dword [i], eax

EAX一般用来放置函数的返回值,这在逆向很有用的。如果EAX放不下 就用EDX,如果还放不下就存储指针这样就够了。

ECX 

这个C是count,计数用的,像for while等循环里面的计数,就是放在这个寄存器里面(这也是编译器的一条规则,当然也是建议规则)。

举例说明:

char sz[128] = {0};

它对应的机器指令如何呢?,首先就是给这段内存清0,假如现在eax里面就是sz的地址,那实际上就是一个循环 (下面代码只是大概,目的是为了说明ecx作为计数器的用法)

mov ecx 32
zzzz:mov eax, 0
dec ecx
test ecx
jnz zzzz
先看下编译器的思路,首先eax里面存的是数组的首地址,eax是四个字节,那么ecx表示计数的话,要清零这段内存ecx应该是多少?

每次搬动四个字节,总共128个字节,所以应该是128/4 = 32,(这个过程是编译器计算出32)

所以上面指令依次为:

ecx设置为32

zzzz:将eax清0

ecx减一

如果ecx不为0

跳转到zzzz

这样32次循环之后,整个数组就清零了。(疑问:eax增加没看到

byte word dword

下面几行代码,有什么区别?

char c1 = 1;
shor c2 = 1;
int c3 = 1;
long c4 =1;
不同类型占用的内存长度不同,分别为1字节,2字节,4字节,4字节,那执行的时候cpu如何知道不同的长度?如何知道第一句就是1个字节 第二个是两个字节 第三个和第四个是四个字节?(byte,word,dword)

编译器会把他们编译成不同的机器指令,

mov byte ptr [c1的地址], 1
mov word ptr [c2的地址], 1
mov dword ptr [c3的地址], 1
mov dword ptr [c4的地址], 1
byte是一个字节,word是两个字节,dword是四个字节,这样来区分的。更多的字节,都是通过这些基础的组合。

但是实际的指令不是这样的,因为cpu不能直接将立即数直接放到内存中,必须通过寄存器。所以,先把1放到寄存器里面,再从寄存器转到对应的内存,

比如第一句

mov AL, 1
mov byte ptr [c1的地址], AL

先将1移入寄存器AL,然后将AL移入到c1的地址,大小为1字节
比如一个内存地址:0xFF00EEFF   ,单从这个地址来看你知道它指向的内存多大?根本没法知道,那么我们就利用这些限定符

ptr byte [0xFF00EEFF]

意思是0xFF00EEFF地址1字节大小

空指针异常汇编解释

char* p = NULL;
*p = 9;
首先是把 内存地址p出的值赋值为0,
mov dword ptr [p], 0
然后是*p = 9
...待续

补充

第一,数据只能从寄存器到寄存器,或者从寄存器到内存,或者从内存到寄存器,不能内存到内存,

比如 你就不能写这样的指令:
mov ptr dword [a1], ptr dword [a2]

这还是现在的冯·诺伊曼原理决定的,因为内存和cpu是不同的组件,cpu通过地址总线连接内存,所以数据必须先从内存中运到cpu中(存在寄存器),

然后再从寄存器搬回内存。

第二,看两种写法,有什么区别

mov eax, ebx
mov eax, [ebx]
第一个是把ebx寄存器里面存的值放到eax中 ,加了中括号表示里面值对应的内存地址中的值

比如ebx 现在等于8,那么mov eax, ebx这样eax就等于8了,如果是mov eax, [ebx]那么相当于把内存地址是8处的内存中的值放到eax中

实例讲解

待续。。。




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嗨!对于逆向学习汇编语言的学习笔记,我可以给你一些基本的指导。首先,汇编语言是一种低级语言,它与计算机的底层硬件密切相关。逆向工程则是通过分析和理解已编译的程序来获取程序的内部信息。 以下是一些学习汇编语言和逆向工程的建议: 1. 学习基础知识:了解计算机体系结构、寄存器、内存和指令集等基础概念是必要的。可以先阅读相关的书籍或在线教程,掌握这些基本概念。 2. 掌握汇编语言的语法和指令集:每种计算机体系结构都有自己的汇编语言语法和指令集。选择一种你感兴趣的体系结构(如x86、ARM等),并学习它的汇编语言。 3. 练习编写和调试汇编代码:通过编写简单的汇编代码来熟悉语法和指令集。使用调试器来单步执行代码并观察寄存器和内存的变化。 4. 分析已编译程序:选择一个目标程序进行逆向分析。使用反汇编器将程序转换为汇编代码,并分析代码的逻辑和功能。这有助于理解程序的结构和运行过程。 5. 使用调试器进行动态分析:通过调试器来动态地执行程序,并观察程序在运行时的行为。使用断点、内存查看器和寄存器查看器等工具来分析程序的状态和数据。 6. 学习逆向工程工具和技术:了解常用的逆向工程工具和技术,如IDA Pro、OllyDbg、Ghidra等。掌握这些工具的使用可以提高你的逆向分析能力。 7. 参考优秀资源:阅读与逆向工程和汇编语言相关的书籍、论文和博客,关注相关的社区和论坛。与其他逆向工程师交流经验也是很有帮助的。 记住,逆向工程是一个需要耐心和实践的过程。持续学习和实践将帮助你提高逆向分析的技能。祝你在学习汇编语言和逆向工程的过程中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Barry__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值