核算机实施的是机器代码。机器代码翻译成可读方法就是汇编,也是逆向工程。
在咱们运用gcc的时分实际上是生成了汇编的,只是进程被省掉了,在学习的时分咱们指定优化等级为 -Og
一些在c言语中被省掉的细节在汇编言语中是可见的。
-
程序计数器
: 在x86-64顶用%rip
标明,给出行将实施的下一条指令在内存中的方位 -
整数寄存器补码下标
包含16个命名的方二进制位,别离存储64位的值。这些寄存器能够寄存地址的值或许整数。有的寄存器用来保存一个暂时的状况 -
条件码寄存器
保存着最近实施的算术或许逻辑指令的状况信息。用来完结操控流的改动 -
一组向量寄存器
能够寄存一个或多个整型或浮点数值
让咱们来看书上的关于汇编的一个比如
编写一个linux重启指令mstore.c文件。含有以下内容
long mult2(long, long);
void multstore(long x, long y, lon补码下标怎样增加g *linux常用指令des) {
long t = mult2(x, y);
*des = t;
}
$gcc -Og -S mstore.c #生成汇编文件
$补码怎样求gcc -Og -c mstore.c逆向工程 #会生成二进制文件(.o)
生成一个.o文件和.s文件
查看.s文件中multstore的界说
里补码面每一行标明一条机器指令(除了一些伪指令)
.o文件里边含有的都是二进制数据
要查看补码和原码的转化机器代码的逆向思维练习500题内容,咱们需求运用反汇编器。在linux里边能够运用objdump指令
$ objdump -d mstore.o
mstore.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <multstore>:
0: f3 0f 1e fa en二进制转化器dbr64
4: 53 push %rbx
5: 48 89 d3 mov %rdx,%rbx
8: e8 00 00 00 00 callq d <multstore+0xd>
d: 48 89 03 mov %rax,(%rbx)
10: 5b pop %rbx
1二进制八进制十进制十六进制转化1: c3 retq
生成可实施文件还有一步很重要的就是链接。
假设咱们有一个main.c文件,含有以下代码
#include <stdio.h>
voi逆向成长d multstore(long, long, long *);
int逆向行驶怎样处罚2021 main() {
long d补码运算规则;
multstore(2二进制亡者列车, 3, &d);
printf("2 * 3 ---> %l逆向旅行dn", d);
return 0;
}
long mult2(long a, long b) {
long s = a * b;
return s;
}
咱们能够用以下方法生成可实施文件prog
gclinux操作系统基础知识c -Og -o prog main.c mstore.c
$ objdump -d prog &补码怎样求gt; prog.s
## 里边有这样一段,能够看到几乎和mstore.c反汇编出来是相同的
00000000000011d5 &linux常用指令lt;multstore>:
11逆向选择d5: f3 0f 1e fa endbr64
11二进制d9linux系统: 53 push %rbx
11da: 48 89 d3 mov %rdx,%rbx
11dd: e8 e7 ff ff ff callq 11c9 <mult2>
11e2: 48 89 03 mov %rax,(%rbx)
11e5: 5b pop %rbx
11e6: c3 retq
11e7: 66 0flinux常用指令 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
11ee: 00 00
全部以.
开始的行都是辅导链接逆向行驶扣几分罚款多少钱器和汇编器的伪指令。linux是什么操作系统咱们一般忽略这些字段。
数据格式
Intel用术语字
标明16位数据类型。因此,称32位数为双字,称64逆向工程位数为四字。
大都gcc生成的汇编代码都有一个字符的后缀标明操作数的大小。例如数据传输有四个变种:mo逆向旅行vb(传送字节)、movw(传送字)、movl(传送双字)、movq(传送四字)。l标明双字。汇编代码也运用后缀l
标明四字节整数和八字节双精度浮点数,由于运用的指令不同,所以不会产生歧义。
16个通用寄存器
操作数指示符
数据传送指令
留意,榜首个是源操作数,第二个是意图操作数
将较小的源值复制到较大的意图时有两种扩展方法,零扩展和符号扩展
零扩展是把多出来的位都用0填充,符号扩展则是用符号位填充
cltq
指令没有操作数,总是以寄存器%eax作为源,%rax作为符号扩展的意图
数据传输示例
写这样一段代码
lo逆向思维案例100个ng exchange(long *xp, long y) {
long x = *xp;
*xp = y;
return x;
}
能够看到下面的汇编代码
0000000000000000 <exchange>:
0: f3 0f 1e fa endbr64
4: 48 8b 07 mov (%rdi),%rax
7: 48 89 37 mov %rsi,(%rdi)
a: c3 retq
压入和弹出栈数据
pushq %rbq 等同于
算术和逻辑操作
加载有用地址
加载有用地址指令leaq实际上是movq指令的变形。它的指令方法是从内存读数据到寄存器,实际上并没有引用内存。
让咱们看书中的比如
long scale(long x, lo逆向行驶怎样处罚2021ng y, long z)
{
long t = x + 4 * y +linux 12 * z;
return t;
}
反汇编后是
一元和二元操作
第二组的操作是一元linux指令操作。第三组是二元操作,第二个操作数既是源又是意图,当第二个操作数为内存地址逆向成长时处理器必须从内存读出值。
移位操作
终究一组是移位操作,先给出移位二进制转化器量,然后第二项补码原码反码给出的是要补码下标怎样增加移位的数。能够进行算术和逻辑右移。移位量能够是一个当即数,或许放在单字节寄存器%cl中。当%cl中的值为0xFF时,指令salb会移位7位,salw会移15位,sall会移31位,salq会移linux系统63位。
左移指令有两种: SAL和SHL。两者的效果是相同的,都是在右边填上0。右移指令则不同,SAR实施算术移位二进制转十进制计算器(填上符号位),SHL补码原码反码实施逻辑移位(填上0)。移位操作的意图操作数能够是一个二进制寄存器或linux指令是一个内存方位。逆向成长
特其他算术操作
imulq是补码乘法,mulq是无符号乘法。这两个操作核算128位乘积,两条指令要求一个参数必须在%rax二进制八进制十进制十六进制转化中,而其他一个作为指令的源操作数给出。然后乘积寄存在%rdx(高64位)和%rax(低64位)中,虽然imulq这个姓名能够用于两个不同的乘法操作,可是汇编器能够经过核算操作数的数补码原码反码怎样转化目,分辨出想用哪种指令。来看书中的比二进制方
#include <inttypes.h>
tlinux必学的60个指令ypedef un二进制转化器signed __int128 uint128_t;
void store_uprod(uint128_t *dest, uint64_t x, uint64_t y) {
*dest=x* (uint128_t) y;
}
void remdiv(long x, long y, long *qp, long *rp) {
long q = x / y;
long r = x % y;
*qp = q;
*rp = r;
}
操控
机器代码供应两种根本的初级机制来完结有条件的行为:查验数据值,然后根据查验的效果来改动控linux是什么操作系统制流或许数据流
条件码
除了整数寄存器以外。cpu还维护这一组单个位的条件码寄存器。它们描绘了最近的算术或逻辑操linux系统安装作二进制计算器的特色。最常用的条件码是
拜访条件码
条件码一般不会直接读取,常用的运用方法有三种: 1)根据条件码的某种组合将一个字设置为0或许1。2)能够条件跳转到程序的某个其他的部分。3)能够有条件的传送数据。关于榜首二进制种,咱们称为SET指令
跳转指令
用条件操控来完结条件分支
让咱们来看一个比如
long lt_cnt = 0;
long ge_cnt = 0;
long absdiff_se(long x, long y)二进制手表
{
long result;
if(x < y)
{
lt_cnt++;
result = y - x;
}
else
{
ge_cnt++二进制;
result = x - y;
}
return result逆向旅行;
}
用条件传送来完结条件分支
传统的方法是经过运用操控的条件转移。当条件满足时,程序沿着一条实施途径实施,当条件缺少时,就走其他一条途径。可是补码和原码的转化可能会十分低效。咱们能够运用条件传送指令来完结,愈加符合现代处理器的功用特性