加密与解密笔记--更新中

加密与解密

0x1 基础

0x01 大端小端

大端:12345678h存入后还是12345678,高位字节存入低地址,依序

小端:12345678h存入后变为78563412,低位字节存入低地址,反序

0x02 win api函数

应用程序编程接口,相当于是一个合成了各个功能的函数库,提供应用程序运行所需要的窗口管理、内存管理等功能

windows应用程序->API->系统服务->硬件层

常用函数:

  • hmemcpy{目的数据地址,源数据地址,数据大小}:拷贝数据,当做断点

  • GetWindowsText{句柄,缓冲区地址,复制的最大字符数}:获得文本控件内容

  • GetDlgItem{句柄,控件标识}:获取指定对话框的句柄

  • GetDlgItemText{句柄,控件标识,缓冲区指针,缓冲区长度}:获取对话框文本,成功就返回文本长度

  • messageBox{父窗口句柄,消息框文本,消息框标题,消息框样式}:创建信息框

0x03 句柄

相当于一个唯一的标识,通常为32位,让windows能正确引用对应的对象。当一个进程被初始化的,系统会分配句柄表,句柄值就是索引

0x04 windows消息机制

消息是给应用程序与应用程序之间、应用程序与windows系统间通信的

应用程序实现功能靠消息触发,靠消息响应和处理来完成

流程:事件发生->windows把输入的消息放入系统消息队列->拷贝到相应的应用程序队列->循环检索发给对应的应用程序窗口

常用函数:

  • sendMessage{目的窗口句柄,消息标识,消息的WPARAM,消息的LPARAM}
0x05 保护模式

虚拟内存:简化内存管理,防止多程序间的冲突

应用程序不会直接访问物理内存,应用程序启动时,操作系统会新建一个进程,分配给它2GB的虚拟地址,虚拟内存管理器将应用程序的代码映射到虚拟地址中,并把当前所需要的代码读取到物理地址中。

dll也会映射到虚拟地址,但是都是要和对应的使用的应用程序一起,没有自己私有的虚拟地址。

不同应用程序的虚拟地址是隔离的。

0x2 动态调试

0x01 OD的使用:

L:log

E:executable

M:memory

T:threads

W:windows

Hhandles

C:CPU,默认的主窗口,绝大部分操作,包括了反汇编,信息,数据,寄存器和堆栈

P:patches

K:call stack

B:breakpoints

R:reference

S:source

反汇编窗口:

地址:单击地址可以跳转,再次双击可以返回

机器码:设置或取消无条件断点,F2

汇编代码:可以直接修改

注释:分号(;)可以加注释

信息窗口:

显示寄存器值、API函数、跳转提示等

数据面板:

十六进制显示,ctrl+G可以快速跳转到对应地址

寄存器面板:

单击鼠标右键可以切换显示寄存器的方式

堆栈面板:

显示ESP指向地址的内容,API函数和子程序等

0x3 静态分析

peid用来查壳,ida用来静态分析,做逆向题的时候经常用到

0x01 ida的常用功能

F5 反汇编

0x02 IDC脚本的使用实践

比如用来解密对代码段进行加密的程序

smc(self modifying code)技术,在可执行文件中保存着加密后的数据。只有在程序运行的时候,程序某处的代码就会被调用来解密

书本例子实践:

打开书本里的例子exe

是一个pe32的文件,用ida7.0(32)版本的ida

image-20210712165355470

打开后看到程序入口:

image-20210712164939040

看到了call 401080和401060的操作,点击过去看看

image-20210712165750238

反汇编一下:

image-20210712165645333

看起来像是对401060做了一系列操作

401060的函数如下,无法看出功能

image-20210712165134938

理解401080,是从401060的首位开始,之后的每一位数据和1做异或,运行到401074为止

编写一个idc脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <idc.idc>
static decrypt(from, size, key ) { //from是解密的开始地址,size是大小,key是异或的值
auto i, x;
for ( i=0; i < size; i=i+1 ) {
x = Byte(from); //获取一个字节数据
x = (x^key); //进行异或
PatchByte(from,x); //将一个字节数据放回原处
from = from + 1;//地址加1
}
Message("\n" + "Decrypt Complete\n");
}
static main(){
decrypt(0x401060, 0x15, 0x1);
}

运行:

image-20210712182457179

image-20210712182432116

运行结束:401060函数的数据就被解密出来了

image-20210712182522600

还是无法看出来是什么功能

按u,全部转换成数据:

image-20210712182813147

再按c,ida重新分析,即可得到最终代码

image-20210712182831000

附:IDC常用函数:

读取和修改数据的函数:

  • long Byte(long addr),从虚拟地址addr处读取一个字节值
  • long Word(long addr),从虚拟地址addr处读取一个字(2个字节)值
  • long Dword(long addr),从虚拟地址addr处读取一个双字(4个字节)值
  • long PatchByte(long addr,long val),设置虚拟地址addr处的一个字节值
  • long PatchWord(long addr,long val),设置虚拟地址addr处的一个字值
  • long PatchDword(long addr,long val),设置虚拟地址addr处读取一个双字值
  • void idLoaded(long addr),如果addr包含有效数据,则返回1,否则返回0

用户交互函数:

  • void Message(string fromat,……),在输出窗口打印一条格式化消息,这个函数类似于C语言的printf函数,并接受printf风格的格式化字符串
  • void printf(……),在输出窗口中打印每个参数的字符串表示形式
  • void Warning(string fromat,……),在对话框中显示一条格式化消息
  • string AskStr(string default,string prompt),显示一个输入框,要求用户输入一个字符串值。如果操作成功,则返回用户的字符串;如果对话框被取消,则返回0
  • string AskFile(long doSave,string mask,String prompt),显示一个文件选择对话框,以简化选择文件的任务。你可以创建新文件保存数据(doSave=1),或选择现有的文件读取数据(doSave=0)。你可以根据mask(如*..idc)过滤显示的文件列表。如果操作成功,则返回选定文件的名称;如果对话框被取消,则返回0
  • long AskYN(long deafult,string prompt),用一个答案为“是”或“否”的问题提示用户,如初一个默认的答案(1为是,0为否,-1为取消)。返回值是一个表示选定答案的整数。
  • long ScreenEA(),返回当前光标所在位置的虚拟地址
  • bool Jump(long addr),跳转到反汇编窗口的指定地址
0x03 hiew使用

F5 输入地址后跳转

F3 修改文件内容,直接输入要修改的数字即可

F9 更新,修改完内容后可以更新一下

F10 更新完后文件内容就被修改了

0x4 逆向分析技术

启动函数:

编译器会生成的一个代码,用来完成初始化进程,然后才会执行winmain函数。各编译器有各自的启动函数。启动函数在分析的时候可以略过

函数:
  • 组成:函数名,入口参数,返回值,函数功能

    CALL指令:会保存返回信息(它之后的指令的地址),遇到RET的时候就返回。CALL后跟着的就是被调用的函数的首地址

  • 参数传递:

    • 堆栈方式:先进后出。

      流程:1、压入函数结束时应返回的地址和需要的一些参数

      ​ 2、函数使用EBP指针+偏移量对堆栈中的参数进行寻址,然后取出进行操作

      ​ 3、函数使用RET返回,CPU把EIP设为之前堆栈里存入的应返回的地址,继续执行

      一般用EBP存取堆栈,也会用ESP堆栈指针来寻址,结合栈溢出学习看

    • 寄存器方式:一部分参数使用寄存器,用完的话剩下的用堆栈

    • 通过全局变量进行隐含参数的传递

  • 返回值:

    一般放在EAX中返回,如果结果超过了EAX的容量,其高32位就会放到EDX中

数据结构:
  • 局部变量:

    在堆栈中进行分配,函数执行完就释放。或者直接存在寄存器中。

  • 全局变量:

    作用于整个程序,放在全局变量的内存区,通常位于一个固定的位置

  • 数组:

    在内存中按顺序连续存放在一起,一般用基址+偏移量来访问

控制语句:

CMP:

JZ:

指令修改:

替换一个字节:90 nop

0x5 常见的保护技术

0x4 解密

0x5 PE文件

0x6 脱壳

0x7 保护

0x8 PEDIY