12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 430|回复: 0

逆向基础笔记十一 汇编C语言基本类型

[复制链接]
发表于 2021-7-18 18:05:46 | 显示全部楼层 |阅读模式
继续更新个人的学习笔记,
其它笔记传送门
逆向底子笔记一 进制篇
逆向底子笔记二 数据宽度和逻辑运算
逆向底子笔记三 通用寄存器和内存读写
逆向底子笔记四 堆栈篇
逆向底子笔记五 标志寄存器
逆向底子笔记六 汇编跳转和比较指令
逆向底子笔记七 堆栈图(重点)
逆向底子笔记八 反汇编分析C语言
逆向底子笔记九 C语言内联汇编和调用协定
逆向底子笔记十 汇编寻找C步伐入口
逆向底子笔记十二 汇编 全局和局部 变量
逆向底子笔记十三 汇编C语言范例转换
逆向底子笔记十四 汇编嵌套if else
逆向底子笔记十五 汇编比较三种循环
逆向底子笔记十六 汇编一维数组
逆向底子笔记十七 汇编二维数组 位移 乘法
逆向底子笔记十八 汇编 结构体和内存对齐
逆向底子笔记十九 汇编switch比较if else
逆向底子笔记二十 汇编 指针(一)
逆向底子笔记二十一 汇编 指针(二)
逆向底子笔记二十二 汇编 指针(三)
逆向底子笔记二十三 汇编 指针(四)
逆向底子笔记二十四 汇编 指针(五) 系列完结
C语言基本范例

不同于寻常的C语言基本数据范例的学习,这里以汇编的形式来学习不同数据范例的存储方式和差异
C语言的数据范例

C语言的基本范例属于C语言的数据范例的一部分:

这里先从最简单的基本范例进行入手学习,在学习基本范例之前再温故一下先前学习过的汇编的数据范例
汇编的数据范例

数据范例名称位BYTE字节8BITWORD字=2字节16BITDWORD双字=4字节32BIT整数范例

C语言的整数范例有:char short int long
整数范例位字节对应汇编char8BIT1字节byteshort16BIT2字节wordint32BIT4字节dwordlong32BIT4字节dword大家大概会觉得疑惑,为什么int和long所表示的貌似一样?
这其实是历史遗留问题,在以前的16位计算机中,int的长度位2字节,但是在32位计算机中,int范例酿成了4字节,而long范例原来便是4字节,现在在仍然是4字节
存储方式

接下来从汇编的角度来看看整数范比方何存储
#include "stdafx.h"int main(int argc, char* argv[]){        char a=0xFF;        short b=0xFF;        int c=0xFF;        long d=0xFF;        return 0;}

语句对应汇编单元char a=0xFF;mov         byte ptr [ebp-4],0FFhbyteshort b=0xFF;mov         word ptr [ebp-8],offset main+20h (0040d4e0)wordint c=0xFF;mov         dword ptr [ebp-0Ch],0FFhdwordlong d=0xFF;mov         dword ptr [ebp-10h],0FFhdword超出数据宽度赋值

上面的赋值都是在基本范例的数据宽度之内,那么如果超出数据宽度会如何?
修改赋值的内容为0x123456789
#include "stdafx.h"int main(int argc, char* argv[]){        char a=0x123456789;        short b=0x123456789;        int c=0x123456789;        long d=0x123456789;        return 0;}然后再观察反汇编代码


语句对应汇编实际赋值单元char a=0x123456789;mov         byte ptr [ebp-4],89h89hbyteshort b=0x123456789;mov         word ptr [ebp-8],offset main+20h (0040d4e0)6789hwordint c=0x123456789;mov         dword ptr [ebp-0Ch],23456789h23456789hdwordlong d=0x123456789;mov         dword ptr [ebp-10h],23456789h23456789hdword不难发现,所有赋值语句全部都高位截断了,即高位的部分全部舍去,只赋值了数据的低位
有符号数和无符号数分析

整数范例分为有符号(signed)和无符号(unsigned)两种
默认就是有符号的范例
通过汇编观察有符号和无符号在内存中存储时是否有差别,这里以char 为例
#include "stdafx.h"int main(int argc, char* argv[]){        char signed a=0xFF;        char unsigned b=0xFF;        return 0;}
我们发现无符号数和有符号数在内存存储中并无差别,再一次印证了我们前面所学的:计算机并不关心数据是有符号数还是无符号数,决定一个数据是有符号数还是无符号数的是使用数据的我们,同一个数据使用不同的方式来解析
了解了有符号数和无符号数的本质后,再来谈谈有符号数和无符号数的注意事项
有符号数和无符号数注意场景


  • 范例转换
  • 比较巨细
  • 数学运算
比较巨细

同为有符号数时

#include "stdafx.h"int main(int argc, char* argv[]){        char a=0xFF;        char b=1;        if(a>b){                printf("a>b\n");        }else if(ab){                printf("a>b\n");        }else if(ab){        printf("a>b\n");}
比较无符号数

char unsigned a=0xFF;char unsigned b=1;if(a>b){        printf("a>b\n");}
我们发现这里的使用的jcc语句都是jle:jump less equal 小于即是才跳转(有符号数),和我们的a>b正好相反
但是我们会发现在有符号数那边使用了movsx指令,该指令为汇编语言数据传送指令MOV的变体。带符号扩展,并传送。
即它会将char从原本的byte扩展到dword,这样一来数据长度被扩展以后,自然就可以使用同一个jle指令来进行比较
int的比较

前面char的比较是通过数据宽度的扩展来实现比较的,那么当使用int时,无法扩展符号的数据宽度时,如何比较?
将上面的char改为int后再次观察反汇编代码
比较有符号数

int a=0xFF;int b=1;if(a>b){        printf("a>b\n");}
比较无符号数

int unsigned a=0xFF;int unsigned b=1;if(a>b){        printf("a>b\n");}
差别

我们可以发现,同样是比较,比较无符号数和有符号数时,分别对应两个不同的jcc语句
比较jcc语句含义比较有符号数jle main+3Dh(0040d7ed)小于即是则跳转 (有符号数)比较无符号数jbe main+3Dh(0040d7ed)小于即是则跳转 (无符号数)浮点范例

C语言的浮点范例分为float和double
存储方式和规范

float和double在存储方式上都是遵从IEEE规范
float的存储方式如下图所示:

double的存储方式如下图所示:

由于double的长度比较长,我们下面就用float作为例子,实际上,double不过是比float精度更高了,在将浮点数转化为存储到内存中的二进制的步骤几乎一致
转化步骤

将一个float型转化为内存存储格式的步骤为:

  • 先将这个实数的绝对值化为二进制格式
  • 将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字的右边
  • 从小数点右边第一位开始数出二十三位数字放入第22到第0位。
  • 如果实数是正的,则在第31位放入“0”,否则放入“1”
  • 如果n是左移得到的,说明指数是正的,第30位放入“1”。如果n是右移得到的或n=0,则第30位放入“0”
  • 如果n是左移得到的,则将n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位。 如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位
看起来很复杂QAQ,但联合下面的实例来看就还好(。・∀・)ノ゙
在转化步骤中的第一步,又分为整数部分的二进制化和小数部分的二进制化
十进制整数二进制化

采用除留余数法
比如将11转化成二进制数
计算余数11/2=515/2=212/2=101/2=010结束11二进制表示为(从下往上):1011
注意到只要除以后结果为0便结束了,任意整数不断除以2最终都会即是0,因此所有整数都可以用二进制来准确表示
十进制小数二进制化

采用乘二取整法
比如将0.9转化为二进制数
计算取整数部分0.9*2=1.810.8(前面结果的小数部分)*2=1.610.6*2=1.210.2*2=0.400.4*2=0.800.8*2=1.610.6*2=1.21…………0.9二进制表示为(从上往下):110011……
很显然,上面的计算过程循环了,也就是说*2永久不大概消灭小数部分,这样算法将无限下去。很显然,并非所有的小数都可以用二进制准确表示,就和十进制里也无法准确表示出1/3一样
实例

8.25f

#include "stdafx.h"int main(int argc, char* argv[]){        float i=8.25f;        return 0;}我们用反汇编检察8.25f

00401028   mov         dword ptr [ebp-4],41040000h我们会发现8.25f的表现形式为41040000h,接下来我们就来研究这个41040000h是怎么来的
一步步按先前提到的转化步骤来:
实数的绝对值化为二进制格式

先处理整数部分8.25
计算余数8/2=404/2=202/2=101/2=01整数部分8转化为二进制:1000(从下往上)
再处理小数部分8.25
计算取整数部分0.25*2=0.500.5*2=1.010.25转化为二进制可表示为:01(从上往下)
于是8.25用二进制可表示为1000.01
添补尾数

接下来先添补尾数部分
先将二进制数转为用科学计数法表示
1000.01=1.00001*2的3次方        (小数点向左移动3位 指数为3)
1.**00001***2
就是将小数点背面的23位填入尾数部分,我们这里小数部分恰好能够准确地转化为二进制数,于是剩下的部分用0添补即可
如果是前面的0.9转化为的0.110011……=1.1100……*2的-1次方
则是截取小数点背面的23位填入1100……
符号位指数部分尾数部分占用空间1823存储内容00001000000000000000000此时尾部部分已经添补完毕,再添补符号位
添补符号位

符号位就简单多了,正数添补0,负数添补1即可
这里我们的8.5f是正数,填0结束
符号位指数部分尾数部分占用空间1823存储内容000001000000000000000000添补指数部分

指数部分的最高位添补看前面是前面将二进制数科学计数法化时,是进行了左移还是右移,左移填1,右移填0
前面我们得到了8.5f的转化:
1000.01=1.00001*2的3次方        (小数点向左移动3位 指数为3)
很明显我们的是左移,因此,最高位填写1
剩下的部分则是用指数减去1后二进制化添补即可
8.5f的指数为3,3-1=2
2的二进制为10
所以指数部分应该为:
10000010
于是整个添补完成
符号位指数部分尾数部分占用空间1823存储内容01000001000001000000000000000000统共为0100 0001 0000 0100 0000 0000 0000 0000
转化为十六进制为4 1 0 4 0 0 0 0 0
和我们前面用汇编看到的结果一致
-8.25f

#include "stdafx.h"int main(int argc, char* argv[]){        float i=-8.25f;        return 0;}
00401028   mov         dword ptr [ebp-4],0C1040000h-8.25f和8.25f相差的只有符号位,于是将前面的8.25f的符号位改为1即可
符号位指数部分尾数部分占用空间1823存储内容11000001000001000000000000000000也就是1100 0001 0000 0100 0000 0000 0000 0000
转为十六进制是 C 1 0 4 0 0 0 0
和前面反汇编看到的结果一致
0.25f

这次看个纯小数在内存中如何存储,仍然采取相同的套路
实数的绝对值化为二进制格式

计算取整数部分0.25*2=0.500.5*1=1.010.25f转化为二进制:0.01
添补尾数

科学计数法表示:0.01=1.0*2的-2次方        (小数点向右移动2位 指数为-2 )
尾数添补0,1.0小数点背面全为0,于是尾数全部填0即可
符号位指数部分尾数部分占用空间1823存储内容00000000000000000000000添补符号位

0.25f是正数直接添补0即可
符号位指数部分尾数部分占用空间1823存储内容000000000000000000000000添补指数部分

科学计数法表示:0.01=1.0*2的-2次方        (小数点向右移动2位 指数为-2 )
向右移动,指数部分最高位填0
指数为-2,-2-1=-3
将-3转化为二进制:-3的十六进制对应fd,fd转为二进制:1111 1101
不知道为什么-3对应fd的可以看这里:逆向底子笔记二 数据宽度和逻辑运算
我们发现-3转为二进制共有8位,但是指数部分统共也只有8位,其中最高位还用作表示是右移添补了0,于是只截取低7位添补进指数部分剩下的内容
于是整个添补完成
符号位指数部分尾数部分占用空间1823存储内容00111110100000000000000000000000统共为0011 1110 1000 0000 0000 0000 0000 0000
转化为十六进制为3 e 8 0 0 0 0 0
接下来用反汇编验证一下:

得到的结果是一致的,好耶ヽ(✿゚▽゚)ノ

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-26 17:27 , Processed in 0.109375 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表