加密与解密 基础篇/win API/小端序大端序

news2024/11/26 10:36:11

1.1加密和解密的概念

是侧重于windows 的加密保护和解密技术

首先我们先要了解

软件逆向工程

可执行程序->反编译->源代码

这就是逆向工程

接着

逆向分析技术是什么

静态调试 和动态调试 主要分为这俩类

1.通过软件的执行 来分析程序

我们可以通过阅读程序的执行 或者说明 来了解程序是怎么执行的

2.静态分析技术

通过IDA这种软件 可以实现静态分析

主要是通过人机交互实现 在用户输入的正确 错误来判断 程序

3.动态分析技术

如果我们需要了解细节 静态调试 还是不够的 所以我们需要通过动态调试

可以说 静态调试 是我们的第一步

动态跟踪 才是分析软件的关键

主要工具有 OllyDbg WinDbg等 

对软件进行一步一步的分析

这里就出现 为什么要进行动态分析的疑问

程序执行 有的时候不是一个函数就执行结束
是多模块的执行结果 
前一个执行结果是后一个输入结果是常有的事情
只有跟踪得到前一个的结果 我们才可以看到后面的事情
并且 如果出现switch这种函数 会有许多分支 如果单单使用静态
是无法得出结果的


并且 在程序执行的时候 有一些 是开始的程序对后面程序的初始化
并不依靠重定向


如果一个程序 具有加密程序 防止非法阅读 这就是需要动态调试

加密程序既要组织跟踪 又要对下一程序的明文进行解密 如果单单依靠静态
是无法得到的

那我们如何有效的进行动态调试呢

(1)对软件进行粗跟踪
就是进行大块大块的跟踪 遇到 CALL REP LOOP指令的时候
不进行跟踪 而是根据执行结果 判断程序的运行

因为程序开始执行 只有一个关键程序是我们需要的
如果每一个程序都细心分析 那么就浪费时间

这里就需要注意 如何设置断点

需要了解Win32 API函数

例如 拦截对话框 
我们就要对MessageBoxA函数进行拦截 对这个函数进行断点 
程序只要一调用这个函数 就会进行中断

对这个函数进行断点 我们就可以对这个函数的执行进行判断

(2)对关键部分进行细跟踪

这个是建立在对程序进行粗跟踪后 我们就可以得到我们需要分析的模块
这样 我们就可以对我们关心的程序进行具体 详细的跟踪

一般情况下 我们需要对关键部分进行多次的跟踪 才可以了解程序的执行

每一次都记录下来 关键的中间结果和指令地址 这样就会对分析有很大的帮助

1.2文本字符

我们最熟悉的就是ASCII码

ASCII码

是通过 7位二进制 来表示 128个字符

百度百科上就能找到

因为ASCII 只能表示 128字符 所以 有了通过ASCII的衍生和扩展

Unicode

是一个ASCII的扩展 在windows中 通过2字节对其进行编码

所以 我们也称呼 Unicode为 宽字符集

使用 0~65535的双字节无符号数 对每个字符进行编码
所有字符都是 16位的 其中所有的7位ASCII都被扩展为16位的Unicode
(这里高位扩充的 都为0)
例如 pediy的ASCII码是

70h 65h 64h 69h 79h

其Unicode码为

0070h 0065h 0064h 0069h 0079h

这里我们需要知道

Intel处理器 在内存中将一个字存入存储器 需要占用相继的2个字节

并且这个字符 在存放的时候 是按照Little-endian方式存入

低位字节存入低地址 高位字节存入高地址

 字节存储顺序

这里就是上面的 Little-endian

这里就是 字节该以什么方式进行传输
Little-endian(小端序)
低字节存入低地址 高字节存入高地址
Big-endian(大端序)
高字节存入低地址 低字节存入高地址

12345678h 存入方式

一般来书 
x86系列CPU都是小端序 Little-endian存入方式

PowerPc通常是大端序 Big-endian存入方式

注意 大端序在网络协议中 经常使用 所以也叫做 网络字节序

1.3Windows操作系统

win32API函数

对调试程序 是要和系统基层打交道 所以我们需要了解API函数的基础

对我来说 API 我只知道是一个接口

而API其实是 应用程序编程接口

对于 windows开始占据主导位置

windows需要开发出为人提供的应用程序

但是windows编程人员 只有 API函数

这个函数提供应用程序需要的 对内存管理 窗口管理 图形设备接口等服务功能

这些功能 通过 函数库 组合在一起

叫做 Win API

Win API子系统 负责将API调用 转换为 windows操作系统的系统服务调用

可以认为 API就是windows框架的基石

他下面是 windows系统操作核心 上面是应用程序

 这里就是开始枯燥的解读

16位的windows API叫做 Win16 (Windows 1.0~3.1)

用于 32位的windows的API叫做 Win32 (windows 9x/NT/2000/XP/7/10)

64位的windows API的功能和名称 基本没有变化
还是使用的是32位的函数名 只不过是通过 64位代码实现

API调用在Win16到Win32的转变中 保持兼容 并且在功能和数量上进行了增加

Windows 1.0 只有 不到450个函数 现在已经有几千个了
所有的32位windows 都支持 Win16 API(确保和旧程序的兼容)和Win32 API(确保新程序的运行)

在windows NT/2000/XP/7和windows 9x 的工作方式不同

在windows NT/2000/XP/7中 Win16函数是通过 一个转换层 来变为 Win32函数调用
然后再被系统处理

在windows 9x中却相反 win32函数调用 是通过 转换层 转换为win16函数调用 
然后再被系统处理
因为windows 9x 使用的是 16位代码模式
而windows NT/2000/XP/7 使用的是32位代码模式 
所以是不一样的
windows 的运转核心是动态链接
windows提供了非常丰富的应用程序可利用的函数调用

这些函数调用 采用动态链接库 DLL 实现

在windows 9x中 DLL 位于 \WINDOWS\SYSTEM子目录中

windows NT/2000/XP/7中 DLL位于系统安装目录的 \SYSTEM和\SYSTEM32子目录中


在早期的系统 
windows主要依靠3个动态链接库 实现 分别代表了windows 3个子系统

Kernel(由Kernel32.dll)实现 :操作系统核心功能服务 主要包括了
进程和线程的控制 内存管理 文件访问等

User(由USER32.DLL)实现:负责处理用户接口 包括键盘 鼠标的输入,窗口和菜单管理等

GDI(由GDI32.DLL)实现:图形设备接口,允许程序在屏幕和打印机上显示文本和图像

除了上面的模块 windows还提供了很多的DLL 来支持更多的功能

包括 对象安全性,注册表操作(ADVAPI32.DLL)

公共对话框(COMDLG32.DLL)

用户界面外壳(SHELL32.DLL)

网络(NEWAPI32.DLL)

Win API是基于 C语言的接口

但是 Win API 可以通过不同的语言进行编写的程序调用

Unicode影响了计算机的每个部分

对操作系统和编程语言的影响最大

NT系统是使用Unicode标准字符集进行开发

其核心完全使用 Unicode函数工作的 
如果希望调用一个windows函数 并且传递他一个ANSI字符串(是一个扩展的ASCII字符集)

系统会先把ANSI字符串转为Unicode字符串
然后进行传入操作系统

如果程序希望返回ANSI字符串

那么系统会把Unicode字符串变为 ANSI 然后返回

所以 在NT框架下 win32 API 能接受 Unicode和ANSI 两个编码方式

但是他的内核 只能接受Unicode字符集

虽然这些对于用户都是透明的 但是转换字符串需要消耗资源
在Win 32 API函数字符集中 "A"表示 ANSI "W"表示 Widechars(就是Unicode)
ANSI通常是单字节方式
Unicode通常是宽字节方式 这样可以处理双字节字符

如果程序在编写的时候 使用了MessageBox函数 
就会去调用这个函数 可是实际上 在USER32.DLL中 
并不会存在这个函数的入口 而是存在 MessageBoxA 和MessageBoxW 这两个函数入口

而这不是我们自己选择的 在我们调用了MessageBox函数
开发工具的编译模块 就会自动根据设定来决定使用A 还是 W 


直白的说 MassageBox是一个宏定义 在不同环境下变为A W类型

这里给出MassageBox函数的原型 这个函数主要是在用户模块中创建和显示信息框

int MassageBox{
    HWND hwnd,       父窗口句柄
    LPCTSTR lpText,    消息框文本地址
    LPCTSTR lpCaption,    消息框标题地址
    uint uType    消息框样式
};

我们可以再看一看windows 2000中 MassageBoxA函数的内部结构

int MassageBoxA{
    MessageBoxExA{  调用这个函数 MessageBoxExA函数
    MBToWCSEx()  将MessageBoxA的消息框的主体文字转换为 Unicode字符串
    MBToWCSEx()  将MessageBoxA的消息框的标题栏的文字转为Unicode字符串
    MessageBoxExW() 调用这个函数 MessageBoxExW
    HeapFree() 释放内存
    }
};

MassageBoxExA其实是一个替换翻译层 用于分配内存

并且把 ANSI字符串变为Unicode字符串

所以系统调用Unicode的MassageBoxExW执行

所以如果应用程序是ANSI版本的 就需要更多的内存和CPU资源

如果是Unicode版本 就是符合NT框架 执行效率就会快很多

win32程序大量调用系统提供的API函数 在win32平台的OllyDbg

恰好有对API函数设置断点的强大功能 所以掌握常见API函数的 用法 会给程序的跟踪调试带来大的方便

WOW64

WOW64是64位操作系统上的子系统 可以使大多数32位程序应用在不修改的情况下运行在64位上

64位的windows 除了带有64位操作系统应有的系统文件 还带着32位系统的系统文件

64位系统的系统文件存放在SYSTEM32的文件夹中 在\Windows\system32文件夹中

包含着原生的64位映像文件

为了兼容32位程序 还增加了\Windows\SysWOW64文件夹 里面就存放着32位系统文件

64位程序 会加载System32目录下64位的kernel32.dll user32.dll ntdll.dll
当32位程序开始加载的时候 WOW64会建立32位的ntdll.dll所要求的环境
并且把CPU模式变为32位模式
并且开始执行32位的加载器
这样就会像在32位的机器上一样


WOW64会对32位的ntdll.dll调用重定向到ntdll.dll(64位) 
而不是发出原生的32位系统调用指令 WOW64接着重新转位64位模式
捕获系统调用有关的参数 发出64位的系统调用 如果原生系统返回了
WOW64在返回32位模式之前 将所有输出参数从64位转为32位


简单来说WOW64为32位程序提供虚拟的32位环境
然后如果需要API的时候 先到64位中找到对应的API 然后翻译成32位的
然后输入给程序

Windows消息机制

Windows是一个消息驱动式系统 windows消息提供在应用程序和应用程序之间、应用程序和Windows之间

应用程序想要实现的功能 由消息触发 通过消息的响应和处理完成

Windows系统有两个消息队列 :
系统消息队列
应用程序消息队列

计算机的所有输入设备都是Windows监控
每当一个事情发生的时候 Windows先把输入 的消息放入系统消息队列
再把输入的消息复制到相对应的应用程序队列中 
应用程序中的消息循环在他的消息队列中检索每个信息 
然后发送给相应的窗口函数


每一个事情的发生 都要经历上面的过程

消息是非抢先性 就是 无论时期是否急缓 都是按照到达进行排队
(一些系统消息除外) 所以容易导致一个实时事情无法及时处理

因为Windows本身是由消息驱动的 所以在调试跟踪的时候 会得到一个相当底层的答案

下面是Windows常见的消息函数

SendMessage函数
这个函数作用是调用一个窗口函数 将一条消息发给那个窗口 
除非消息处理完毕 否则函数不会返回

LRESULT SendMessage{
    HWND hWnd,     目的窗口的句柄   HWND 是一个数据类型 代表一个窗口的句柄
    UINT Msg,        消息标识符        UINT无符号整数
    WPARAM wParam,    消息的WPARAM域
    LPARAM LParam        消息的LPARAM域
};

如果消息投递成功 就返回 TRUE
WM_COMMAND消息
当用户从菜单或者按钮中选择一条指令或者一个控件的时候
把他发送给他的父窗口的
或者 一个快捷键被释放时发送

下面是C++对WINUSER.H的定义 WM_COMMAND所对应的16进制是 0111h

WM_COMMAND
    wNotifyCode = HIWORD(wParam);      通告代码
    wID = LOWORD(wParam);              菜单条目 空间或者快捷键标识符
    hwndCtl = (HWND)lParam;            控件句柄

返回值 如果应用程序处理了这个消息 那么返回值为0
WM_DESTROY
当一个窗口被销毁的时候 发送这个消息 该消息的十六进制是 02h 没有参数

返回值 如果应用程序处理这个消息 那么返回值为 0 


作用就是销毁程序 释放内存
WM_GETTEXT
应用程序发送一条WM_GETTEXT的消息 把一个对应窗口的文本复制到一个由呼叫程序提供的缓存区中 
这个的十六进制是 0Dh

WM_GETTEXT
    wParam = (wParam) cchTextMax;    需要复制的字符数
    lParam = (LPARAM) lpszText;       接受文本的缓存区地址


返回值 是被复制的字符数
WM_QUIT
当系统调用 PostQuitMassage函数的时候 生成 WM_QUIT消息 十六进制是 012h

WM_QUIT
    nExitCode = (int)wParam;     退出代码


没有返回值

停止循环 退出程序
WM_LBUTTONDOWN 
光标停在一个窗口的客户区 并且按下左键的时候 WM_LBUTTONDOWN发生消息
如果光标没有被捕获 就发给光标下的窗口 如果捕获了 就发送 已经捕获动作的窗口

WM_LBUTTONDOWN
fwKeys = wParam;                key旗帜
xPos = LOWORD(lParam);          光标的水平位置  
yPos = HIWORD(lParam);          光标的垂直位置


返回值 如果应用程序处理了这条消息 那么返回值为0

虚拟内存

默认情况下 32位 Windows操作系统的地址空间在4GB内 win32点平坦内存模式

可以让每一个进程都有自己的虚拟空间

对32位进程来说 这个地址空间是4GB

因为32位指针有00000000h~FFFFFFFFh 的任意值

这个时候 程序的代码和数据都存放在同一地址空间中 不需要区分代码段和数据段

虚拟内存并不是真实的内存
他是通过映射的方式 把可用虚拟内存地址可以达到4GB大小
所以每一个程序可以得到2GB点虚拟地址 剩下的2GB留着操作系统自用

在 Windows NT 应用程序甚至可以得到3GB

Windows 是一个分时的多任务操作系统 
CPU时间 再被分成一个一个时间片后分配给不同的程序
在一个时间片中 和这个程序不相干的不会映射到线性地址中 
所以每个程序都有自己的4GB寻址空间 互不干扰 
在物理内存中 操作系统和系统DLL代码需要供给每一个程序调用
所以他们在任意时刻都被映射 
用户的 EXE程序 只会在执行的时间片中被映射 用户 DLL则是有选择的被映射
下面是虚拟内存的实现方法和过程

1 应用程序执行启动 操作系统创建一个进程 给这个程序分配2GB的虚拟地址(只是地址 不是空间)
2 虚拟内存管理器把应用程序的代码映射到和应用程序虚拟地址中的某个位置 并且把当前需要的代码写入物理地址(虚拟地址和应用程序代码在屋里内存中的位置是没有关系的)
3 如果使用DLL DLL也会被映射到虚拟地址空间中,在需要的时候才会写入物理地址
4 其他项目(数据,堆栈等)的空间从物理内存进行分配 然后被映射到虚拟地址空间中
5 应用程序通过使用其虚拟地址空间的地址 开始执行 然后 虚拟内存管理器把每次内存访问映射到物理地址

总结

应用程序不会直接存入物理空间中
虚拟内存管理器通过虚拟地址的访问请求来控制所有物理空间的访问
每个程序都有自己独立的4GB空间 不同应用程序的地址空间是相互隔离的
DLL程序没有自己的空间 他们总是被映射到其他应用程序的地址空间中 作为一部分进行执行
(因为如果DLL不和应用程序处于同一空间 就无法调用DLL)

使用虚拟内存的好处是 简化了内存的管理 弥补了内存的不足 可以防止多任务下程序的冲突

在64位CPU最大的寻址空间是 16TB

实际应用中

64位的windows 7 支持8~192GB点聂村

64位windows 10 支持 128GB~2TB的内存

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/551765.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这个Set接口真牛逼

偶然间看到 java.util 包下的 Set 接口,看着好搞笑哈哈哈哈哈哈哈 包括了如下几个方法: 创建包含0个元素的不可修改的Set集合创建包含1个元素的不可修改的Set集合创建包含2个元素的不可修改的Set集合创建包含3个元素的不可修改的Set集合创建包含4个元素…

ROS:laser激光雷达数据格式、发送laser数据、订阅laser数据

一.激光雷达数据格式 图片来源:ROS-订阅与处理激光雷达scan话题_ros激光雷达数据处理_zhhao1326的博客-CSDN博客 # 测量的激光扫描角度,逆时针为正 # 设备坐标帧的0度面向前(沿着X轴方向) Header header # Header也是一…

Java学习路线(8)——面向对象基础(2)

一、static关键字 概念: static是静态的意思,可以修饰成员变量和成员方法。当修饰成员变量时,在内存中只存储一份,可以被共享访问、修改。当修饰成员方法时,可以被共享访问,也被称为公共方法。 静态成员变…

【linux网络】防火墙规则二:SNAT策略与DNAT策略

防火墙规则 一、SNAT策略1.1SANT的原理与应用1.2SNAT实验 二、DNAT策略2.1DNAT的原理与应用2.2DNAT实验 三、Linux的抓包工具tcpdump3.1补充知识 四、防火墙规则的备份和还原 一、SNAT策略 1.1SANT的原理与应用 SNAT 应用环境:局域网主机共享单个公网IP地址接入In…

2023.05.21 学习周报

文章目录 摘要文献阅读1.题目2.背景3.现存问题和解决方法4.方法4.1 Variational mode decomposition (VMD)4.2 Bidirectional LSTM 5.实验5.1 数据标准化5.2 评价指标5.3 实验过程及结果 6.结论和展望 优劣解距离法有限元1.求解一个简单的传热问题2.有限元如何实现 总结 摘要 …

vscode远程到服务器(包括WSL)进行GDB调试

工欲善其事必先利其器,这句话不容小觑,调试工具做的好,对开发工作可起到事半功倍。 本文主要讲vscode远程到服务器进行在线GDB调试手段,包含对WSL的远程调试,可以轻松对照源码进行应用程序调试。 文章目录 一、vscode…

【SpringCloud】一、认识微服务

文章目录 1、学习提纲2、和单体架构的比较3、认识微服务4、微服务技术常用框架5、SprigCloud6、服务拆分7、微服务远程调用 1、学习提纲 相比传统单体架构,微服务的整体架构如下图: 再引入日志、监控、持续集成、持续部署,就成了下面这个图&…

RocketMQ 的介绍和基本使用

介绍 在 RabbitMQ 的基本概念和五种模式使用示例 前半部分介绍了 MQ 的应用场景,以及多个 MQ 产品的对比,那时说到 RocketMQ 的客户端版本只有 Java , 现在 Apache RocketMQ 社区中也增加了 C NodeJS Python Go 的客户端。 RocketMQ 是阿里巴巴开源的一…

iOS正确获取图片参数深入探究及CGImageRef的使用(附源码)

一 图片参数的正确获取 先拿一张图片作为测试使用 图片参数如下: 图片的尺寸为: -宽1236个像素点 -高748个像素点 -色彩空间为RGB -描述文件为彩色LCD -带有Alpha通道 请记住这几个参数,待会儿我们演示如何正确获取。 将这张图片分别放在…

从零开始 Spring Boot 32:AOP II

从零开始 Spring Boot 32:AOP II 图源:简书 (jianshu.com) 之前写过一篇文章从零开始 Spring Boot 26:AOP - 红茶的个人站点 (icexmoon.cn),讨论了AOP的基本用法,但那篇文章相当粗疏,对Spring中的AOP技术讨…

免费快速部署ChatGPT线上聊天网页:ChatGPT API + Github + Railway

1、使用工具 (1)需要自己生成的openai api,获取API的网站:openAI API 获取方式:OpenAI的API key获取方法 (2)本次使用该参考项目进行部署:chatweb 需要将该项目fork到自己的仓库里 …

29 SQL——事务操作

create table account (id int auto_increment primary key comment 主键ID,name varchar(18) comment 姓名,money int comment 余额 )comment 账户表;insert into account(id, name ,money)values(null,张三,2000),(nul…

不定积分题型简单总结

不定积分 考研数学复习笔记,用来复习知识点用,如有不足还请指出,Thanks♪(・ω・)ノ 文章目录 不定积分1 原函数/不定积分 概念和性质2 原函数存在定理3 不定积分的基本公式4 不定积分的基本计算4.1 三角代换型…

中间件-RabbitMQ

文章目录 1.什么是MQ1.1 特点1.2 MQ产品分类 2.RabbitMQ2.1.RabbitMQ介绍2.2.使用Docker安装RabbitMQ 3.SpringBoot中使用RabbitMQ3.1.SpringAMQP3.2使用步骤 1.什么是MQ RabbitMQ官方文档 消息队列(Message Queue,简称MQ):是在消息的传输过程中保存消…

SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】

前言 文章内容有点长,建议打开右侧目录导航栏查看。 这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间,做几个变体系统。 闲的无聊,把大学时候做的一个系统进行了重…

git源代码管理

文章目录 git源代码管理git单人本地仓库操作创建远程仓库(github为例)多人开发与冲突分支操作SSH(安全外壳协议) git源代码管理 文档连接:https://git-scm.com/docs git是用于源代码管理,方便多人协同开发…

架构整洁之道上篇(编程范式设计原则)

目录 1.概述 2.编程范式 2.1.结构化编程 2.2.面向对象编程 2.3.函数式编程 3.设计原则 3.1.单一职责原则 3.2.开闭原则 3.3.里氏替换原则 3.4.接口隔离原则 3.5.依赖反转原则 4.小结 1.概述 软件架构的终极目标是,用最小的人力成本来满足构建和维护该系…

2023 操作系统 R 复习大纲( 适用于太理软件 21 级)

目录 01.操作系统的定义 02.操作系统的基本类型及特征 1.批处理操作系统(单、多道) 2.分时操作系统 3.实时操作系统 03.操作系统的功能及特征 04.进程的定义、特征 05.进程基本状态及其转换原因 06.进程互斥、同步 07.进程控制块的内容、作用 …

Java数据类型之整数类型与浮点数

标识符(名字) 作用域 离其最近的大括号 { } !!! 数据类型的分类 赋值时,不可超过数据类型的范围(不可越界) 常量的进制转换 tips:给变量赋值时,值可以为不同…

从代码层面理解Transformer

跑通 代码使用的是 https://github.com/jadore801120/attention-is-all-you-need-pytorch, commit-id 为: 132907d 各模块粗览 Transformer 主要包括一堆参数, 以及encoder和decoder forward的时候主要做了如下操作. 先 pad_mask过encoder过decoder输出logit 从train.py …