任鸟飞C++逆向安全之第一个项目

14 篇文章 5 订阅
13 篇文章 7 订阅

黑眼探光明,逆向寻真理!

为了能够更好的学习零基础逆向安全课程,我们决定C++基础开始说起,懂得正向原理,才能事半功倍的取学习逆向知识。

一、进制及其转换

学习C++和逆向安全,为什么要学习进制?难道说我们日常用的数字还不够么?答案是:当然不够

下面我们就先来看一下什么是进制,常用的进制有哪些,不同进制之间的关系,以及他们之间如何的转换。

进制,又称进位计数制,是人为的一种带有进位的计数方式,我们最常用的进制是十进制,

那么我们就用十进制来对进制的概念做一个深入的了解.

什么是十进制?

10进制非常简单,我们现实生活中最常用的就是十进制

10进制是由 0,1,2,3,4,5,6,7,8,9 10个符号组成的逢10进1的一种进制。

10进制中是没有10这个符号的, 哪个符号来代表10呢?其实是没有的

10是由1和 0 2个符号组成的。

还有哪些其他的进制?

知道了10进制的定义,我们引申出n进制定义

N进制定义:由n个符号组成 逢n进位

N进制中是没有N这个符号的

例如:

2进制有2个符号组成,里面有2吗?没有,逢2进位了,只有 0和1这2个符号,电路开关采用的就是二进制

1小时有60分钟,这是60进制,我们在电子表里是看不到60这个数字的

1天有24小时,这是24进制,同样我们手机里也看不到24点这个时间

再比如1打啤酒是12瓶,这是12进制,还有很多很多其他类型的进制,当然这些进制并不是很常用,也对我们后面的学习没有什么帮助

学习C++和逆向安全需要哪些进制?

由于我们要学习编程的原理,而不只是单单的学习C/C++等编程语言,

所以就要去学习计算机底层实现的原理。

但是计算机只认识2进制,也就是0和1.

实际上我们无论写出什么样的代码,最后都是变成2进制被计算机执行的。

也就是说我们要学习进制,其实主要就是要学习2进制。

以及十六进制,后面我们会知道十六进制就是二进制的简写方式.毕竟二进制及其不方便

进制的转换

进制计算其实我们谁都会,只是我们没有把他抽象成文字,或者说并不熟悉

例如

70秒你立刻就知道是1分钟零10秒,想想怎么算的呢?

25瓶你立刻就知道是两打零1个,又是怎么计算的呢?

自己莫名其妙的就会吧? 只是自己没有总结方法吧?

所以啊,我不是教你知识, 只是引导你使用你已经会的东西.

以上两个例子,就是十进制转其他进制

70/进制 = 70/60 = 1 余10 = 1分10秒

我们再来看下常用的进制转换

1.十进制转二进制

那么十进制3转成二进制等于多少?

3/2 = 1 余1 十进制3 = 二进制 11 是不是很简单呢?

需要除多次的十进制转二进制大家可以不掌握,因为我们只要知道原理就可以了

例如 十进制 12 转 二进制 12 = 1100

12/2 = 6余0

6/2=3余0

3/2=1余1

1/2=0余1

将余数从下向上依次抄写,就是1100

一小箱白酒可以装2瓶 ,一个礼盒可以装2小箱,一大箱又可以装二个礼盒

请问 1大箱是多少瓶? 什么感觉自己还是会的? 答案很简单 8瓶

其实就是对应的二进制转十进制

1000 = 8

1表示1大箱 第一个0表示0礼盒 第二个0表示0小箱 第三个0表示0瓶

2.二进制转十进制

一个十进制数123 ,1为什么在百位?2为什么在十位?3为什么在个位?

实际上123 = 1*10*10 + 2*10 +3 = 1*进制*进制 + 2*进制 +3

2在十位的原因是因为他有2个10,是进位而来的,1在百位是因为有10个10进位而来的

刚才的1000 也是 1*2*2*2+0+0+0 =8

一个二进制111

实际上111 = 1*2*2 +1*2+1 = 7

这样2进制就转换成10进制了

二进制 10000000000 = 十进制 1024

3.拓展内容,十进制转其他进制

十进制数12 如何转成二进制

其实很简单,我们把数值都放到个位,看看他怎么进位即可

我们12全放在个位是不行的,二进制只有1和0,那么我们需要进位、

所以

12/2 = 6 余0

代表我们有6个2进位到十位,余0代表个位为0,我们暂且可以写成60,当然2进制不能有6,所以我们继续进位

6/2 = 3 余 0

代表我们有3个2进位到百位 ,余0代表十位为0,我们暂且写成300,但是2进制不能有3,所以我们继续进位

3/2 = 1 余 1

代表我们有1个2进位到千位 ,余1代表百位为1,我们可以写成1100,里面已经没有除了1和0之前其他的数值,那么我们得到了最终结果1100

十进制123 转成 9进制等于多少? 用同样的方法计算一下

146

十六进制

我们学习了2进制和十进制,下面来学习一下16进制

1.为什么要学16进制?

为什么会牵扯出16进制呢?16进制实际上是2进制的简写方式。

为什么要简写呢?

大家试想一下,如果屏幕上面全都是0和1一串数值,让你去看或则记忆,会是一种上面样的情况

例如

11010100100101000101111101001010101

疯掉了吧?

所以我们必须要有一种简写的方式来帮助我们观看

聪明的人类是这样设计的

4位2进制最小是0000,最大是1111,也就是 0 - 15,那么我们就可以用一位的16进制来表示4位的2进制了,16进制的16的符号分别是0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

例如 1101 我直接可以用 0xD 表示了

11011111 就是0xDF 是不是看起来舒服多了,看起来不那么累了

以后我们看到的二进制,无论是VS的反汇编窗口还是IDA,OD,CE等工具里,全部都是以16进制的形式体现出来的

2.数据宽度,字节和位

1位在10进制中就是表示 0 -9

而在2进制 也就是计算机中表示 0或则1

这是理论上的最小单位 1位,但是应用起来很麻烦

所以我们真正应用的最小单位是 字节 一个字节 等于8位

1字节8位的最大值 = 11111111 转成16进制就是FF

1字节8位的最小值 = 0000000 转成16进制 就是 00

字节是以后我们应用的最小单位 范围为00-FF

进制符号化_拓展

我们来看下十进制的定义 0123456789 10个符号 逢10进1

注意是说的10个符号,这10个符号可以不是0123456789

如果是)!@#¥%……&*( 这10个符号 你还会计算吗

% + …… = !! 能看出来吗?

打乱这种就可以达到加密的效果

提问:1+1=1 正确吗?

9进制 9个符号分别为543672189 (分别对应012345678 )

现在5已经代表0了...

那么

176+829=?

176 和 829 分别对应 643和 758

643+758= 1512

然后转换回现在的定义 4 2 4 3

二、创建项目,了解main函数

学完了进制的概念和转换,接下来我们进入了正式的C++和逆向安全的学习,这里我们采用的工具是VS2019,大家可以到WX公众:任鸟飞逆向的工具资料中进行下载,或者到VS的官网下载Visual Studio 2022 IDE - 适用于软件开发人员的编程工具

1.C语言和C++的关系

在学习C++之前,我们先来了解一下C语言和C++的关系

C语言是过程性语言,而C++则是在C的基础上"++"也就是添加了面向对象编程,函数模板,泛型编程等很多东西

简单来说C就是C++的一个子集,C++ 是C 的超集,C++ 在C语言的基础上增加更多的内容而已

2.编写软件的过程

软件的编写其实是一个很复杂的过程,而我们可以利用工具讲这个过程变的简单化,下面我们来看看这个过程有哪些步骤

源代码---->编译源代码变成目标代码---->链接(将启动代码,库代码,目标代码组合起来)---->可执行代码,

从这个过程中大家可以看到这里需要编译器,链接器等工具

所以这个过程需要一个集成开发环境又称IDE.

就是集合编辑、编译、调试三大功能为一体的工具,我们选择Visual Studio简称VS。

最新版VS2019.VS2022,选择次新版本永远是最明智的选择,所以我们选择2019版本

3.创建第一个程序

启动VS来到初始界面

初始界面,点击创建新项目

然后选择 控制台应用,点下一步

给项目起个合适的名字和目录,点击创建(虽然新版本的VS支持中文名字和目录,

但是还是建议都使用英文命名,这里用中文的目的是为了让大家看得更加清晰)

这个时候,我们只有一个文件,30天入门C++.cpp

.cpp 就是C++文件,英文就是 c plus plus 的意思 即C++,而C语言创建的则是.c

这样第一个项目就创建完毕了.

4.编辑----编译生成----运行----调试

创建完毕的项目,已经有了初始代码

这里暂时不需要我们自己编辑

我们直接编译

下面显示“成功”,没有“失败”就是编译成功了。

5.main函数

一个程序必须要有一个main函数作为入口函数

我们把 原有的代码注释掉

// 注释单行,

/* ... */ 注释一段,

被注释的代码意思就是相当于没有, 不参与编译,但是又方便我们观看,也可以随时取消注释

点生成,出现错误提示

大概意思就是说一个程序必须有一个main 函数,因为他是入口函数。

没有入口函数,程序不知道从哪里开始执行, 简单说,做任何事,你总要是给我一个开始点,逛个商场我们还要从门口开始呢不是吗?

而程序的这个入口点就是main函数,main函数被启动代码调用,相当于被操作系统调用。

启动代码是操作系统和程序的桥梁,C++规定int main固定写法,而且return 0表示程序正常结束

当然也有其他情况,是和启动代码有关的,不在这里做过多研究。

6.运行生成的程序

生成的程序是可以运行的,CTRL+F5

也可以在项目上右键,打开文件夹

也可以打开项目文件夹找到生成程序直接双击

双击后我们发现,程序没有出来

这并不是程序执行失败,而是因为程序一下就执行结束了,我们还没来得及看到他的输出信息。

所以,我们在代码最下面加一句getchar(); 就好了这句代码的意思是等待用户输入信息,所以他不会立刻被执行完毕

开始先抄写,不要抄错

同时也可以点F5的方式,对程序进行调试执行,我们放到后面详细讲解。

7.注意事项

(1)标点符号用英文,尤其喜欢命名中文变量的同学,要给输入法设置成半角符号

(2)区分大小写

(3)开始先抄袭模仿,再学习每一句代码的真实含义,一步步来

8.其他问题

界面打乱了怎么恢复?

可以点击 视图----解决方案资源管理器

也可以,重置或则保存布局

关掉项目怎么重新打开?

项目文件夹中.sln 是打开项目的启动项

.cpp 是我们写的代码

.exe 是给用户的执行程序

三、printf与cout

我们完成第一个C++程序的编写, 并且成功的输出了一行代码,那么这条输出的代码是如何生成的呢?

1.输入输出, 面向过程和面向对象

cout是一个对象, 他来执行输出的动作,

我们把上述代码替换成下面代码来学习,

这是C语言常用的方式,给你一个输入"Hello World" 让printf帮我们在控制台输出结果,

这是一个过程,为什么要这么做呢?

主要原因有2个:

第一,std::cout 即使用了名字空间,又使用了对象,还使用了符号重载,这些名词听起来都很陌生吧

我觉得这2个知识不适合新手上来就学,这样就可以放到后面点的位置再学习,

第二,printf比 std::cout

当然cout比printf 也有很多优势,后面我们会了解,但是基本上 2者的功能是可以互相替代的。

2.printf的含义

print是打印,f 就是format,格式化的意思,合起来是格式化输出字符串的意思

printf("Hello World \n"); 打印双引号中的内容

\n 换行符,不会被打印出来而是直接换行

这里的 \ 叫转义字符,不会被打印,而是联合后面的n成为一个符号

还有\t,即tab制表符等等

有的同学可能会说,那么想打印\ 岂不是打印不出来了?

打印\ 需要写 \\

3.printf也可以这样使用

printf("a = %d ,b = %d \n",30,70);

printf("a+b = %d \n",100);

printf括号中的内容代表传入的参数列表

printf括号中的逗号将参数列表分割成几个部分,表示传入的每个参数

其中的%d表示用后面的参数30和70来依次替换,其中的d代表十进制有符号整数

F5运行后结果为

%d也可以写成%3d,%03d等等格式

也可以用f来代表十进制浮点型等等

F5运行后结果为

我们还可以用%3d来将打印的结果按3位对齐,表示数值占3个宽度,也可以用%04d来将打印结果按4位对齐,表示数值占4个宽度不足4位的部分用0来代替,

的部分用0来代替

F5运行结果为

printf("a = %f \n",12.3456);

其中的%f表示打印一个浮点型的数值,

我们也可以用%.2f来四舍五入保留小数点后两位。

在printf("a = %d ,b = %f \n",11,22.2);中有3个参数

分别为第一个参数"a = %d ,b = %f \n" (参数的概念我们放到后面来讲,这里只要做个了解即可)

第二个参数11

第三个参数22.2

当然如果有更多的%d %f等等,也可以有第四个第五个等等的参数

这里的第二个第三个参数不止可以用数值来表示,也可以用变量来表示

比如

输出结果为

这里的int a = 11;表示申请一个类型为int的变量,并为它赋值11

double b =22.22;表示申请一个类型为double的变量,并为它赋值22.22

4.简单的了解下变量

在printf的逗号后面,我们可以使用数值,也可以使用变量, 变量可以有很多的类型,

比如int 整数型,float小数,double双精度小数等等

%d 不是固定的

%f 打印小数 float 默认6位

%lf 打印double

%.2f 打印2位

%X 打印16进制(0x 或则 h 代表16进制)

5.小数常量的问题

C++ 中默认小数常量都是double 类型(我们在代码中遇到的直接的数值通常都是常量,常量的概念后面会讲到)

在给a赋值时,常常会因为类型不同,生成如下警告

解决方法,在数值后面加一个小写的f

那么float 和double 有什么区别呢?

float只能表示6位,后面的都是假的了,这就是double存在的意义

四、预处理指令之头文件

我们之前已经说过,代码在进行编译前,需要对源文件进行简单的加工,我门把这个操作叫做预处理。、

当对一个源文件进行编译时,系统将自动调用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

C语言提供了多种预处理功能,如宏定义、文件包含、条件编译(兼容不同系统)等,合理地使用它们会使编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。

下面我们着重了解一下预处理指令中的头文件。

我们新建一个类型为.h的头文件,并且在里面加入一条int a = 100;

然后我们回到有main函数的源文件中并且将a进行打印

此时他会提示未定义的标识符“a”。

因为我们并没有在这个文件中定义a这个变量,而是在其他文件中进行的定义,

于是在文件头部添加一条包含头文件的指令#include “hhh123.h”

此时可以编译成功。

包含头文件

有的文件用<>,有的却用"",那么二者到底什么区别呢

<>和"“表示编译器在搜索头文件时的顺序不同,

<>表示从系统目录下开始搜索,然后再搜索PATH环境变量所列出的目录,不搜索当前目录

”“是表示从当前目录开始搜索,然后是系统目录和PATH环境变量所列出的目录。

所以,系统头文件一般用<>,用户自己定义的则可以使用”",加快搜索速度。

一般C++的头文件都是不带.h的,而C的头文件都是带.h的,

头文件的第一句代码都默认,#pragma once 这句 预处理指令,

只要在头文件的最开始加入这条预处理指令,就能够保证头文件只被编译一次。

防止包含了多次,产生错误。

头文件无需死记硬背,只需要跟着课程学下去即可,如果有疑问可以到WX公众:任鸟飞逆向进行留言和交流学习。

五、编写进制转换器

前面我们讲了一些C++的基本概念和指令,这节课我们来利用这些知识去编写一个简单进制转换工具。

在写代码之前,我们要再了解一个新的指令scanf,当然在新版本的VS中我们需要用到scanf_s这个指令

scanf_s("%d",&a);表示为变量a输入一个无符号整数型的数值

这里的%d后面不要加\n换行符

比如

scanf_s("%d",&a);表示为变量a输入一个无符号整数型的数值

这里的%d后面不要加\n换行符

比如

运行结果为

这里的3和4是需要我们自己输入并按回车键的

我们也可以任意输入其他的整数型数值

再输入小数的时候我们尽量用%lf

printf可以传入多个参数来打印多个值,scanf也同样可以

比如

F5运行后输入两个浮点型,中间用英文的“,”隔开,然后回车,结果如下

注意这里的逗号不要输入全角的,否则结果就会变成

这样是错误的

scanf在后面的应用中几乎是用不到的,所以会用即可

运行结果为

这里的3和4是需要我们自己输入并按回车键的

我们也可以任意输入其他的整数型数值

再输入小数的时候我们尽量用%lf

printf可以传入多个参数来打印多个值,scanf也同样可以

比如

F5运行后输入两个浮点型,中间用英文的“,”隔开,然后回车,结果如下

注意这里的逗号不要输入全角的,否则结果就会变成

接下来我们用scanf_s和printf来做一个十六进制和进制的转换器,代码如下

这样我们在输入一个十进制后,会输出它相应的十六进制

这样一个简单的进制转换工具就完成了,当然这只是逆向安全的开始,我们连第一步还没有迈出,随着后面的课程更新,我们会在C++的学习中逐渐的接触和学习逆向知识。

欢迎大家来到WX公众:任鸟飞逆向进行学习交流。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值