2019-04-02 08:28:32 +00:00
|
|
|
|
---
|
|
|
|
|
title: 逆向工程与软件破解
|
|
|
|
|
date: 2019-03-28 15:25:04
|
|
|
|
|
tags:
|
|
|
|
|
- 逆向
|
|
|
|
|
- 破解
|
|
|
|
|
categories: 二进制
|
2021-04-10 19:18:56 +00:00
|
|
|
|
description: 一些逆向的小实验
|
2019-04-02 08:28:32 +00:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# 软件保护方式
|
|
|
|
|
1. 功能限制
|
|
|
|
|
2. 时间限制
|
|
|
|
|
- 运行时长限制
|
|
|
|
|
- 使用日期限制
|
|
|
|
|
- 使用次数限制
|
|
|
|
|
3. 警告窗口
|
|
|
|
|
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553759246/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E5%9B%BE%E7%89%871.png)
|
|
|
|
|
--------------------
|
|
|
|
|
# 分析工具
|
|
|
|
|
1. 静态分析工具
|
|
|
|
|
- IDA
|
|
|
|
|
- W32Dasm
|
|
|
|
|
- lordPE
|
|
|
|
|
- Resource Hacker
|
|
|
|
|
2. 动态分析工具
|
|
|
|
|
- OllyDbg
|
|
|
|
|
- WinDbg
|
|
|
|
|
-----------------------
|
|
|
|
|
# 对抗分析技术
|
|
|
|
|
1. 反静态分析技术
|
|
|
|
|
- 花指令
|
|
|
|
|
- 自修改代码技术
|
|
|
|
|
- 多态技术
|
|
|
|
|
- 变形技术
|
|
|
|
|
- 虚拟机保护技术
|
|
|
|
|
|
|
|
|
|
2. 反动态分析技术
|
|
|
|
|
- 检测调试状态
|
|
|
|
|
- 检测用户态调试器
|
|
|
|
|
- 检测内核态调试器
|
|
|
|
|
- 其他方法:父进程检测;StartupInfo 结构;时间差;通过Trap Flag检测
|
|
|
|
|
|
|
|
|
|
3. 发现调试器后的处理
|
|
|
|
|
- 程序自身退出
|
|
|
|
|
- 向调试器窗口发送消息使调试器退出
|
|
|
|
|
- 使调试器窗口不可用
|
|
|
|
|
- 终止调试器进程
|
|
|
|
|
----------------------
|
|
|
|
|
# PE文件格式基础
|
|
|
|
|
------------
|
|
|
|
|
# 加壳脱壳
|
|
|
|
|
------------------
|
|
|
|
|
# 反调试技术
|
|
|
|
|
反调试技术,程序用它来识别是否被调试,或者让调试器失效。为了阻止调试器的分析,当程序意识到自己被调试时,它们可能改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。
|
|
|
|
|
## 探测windows调试器
|
|
|
|
|
1. 使用windows API
|
|
|
|
|
使用Windows API函数探测调试器是否存在是最简单的反调试技术。
|
|
|
|
|
通常,防止使用API进行反调试的方法有在程序运行期间修改恶意代码,使其不能调用API函数,或修改返回值,确保执行合适的路径,还有挂钩这些函数。
|
|
|
|
|
常用来探测调试器的API函数有:`IsDebuggerPresent` `CheckRemoteDebuggerPresent` `NtQueryInformationProcess` `OutputDebuggString`
|
|
|
|
|
2. 手动检测数据结构
|
|
|
|
|
程序编写者经常手动执行与这些API功能相同的操作
|
|
|
|
|
- 检查BeingDebugged属性
|
|
|
|
|
- 检测ProcessHeap属性
|
|
|
|
|
- 检测NTGlobalFlag
|
|
|
|
|
3. 系统痕迹检测
|
|
|
|
|
通常,我们使用调试工具来分析程序,但这些工具会在系统中驻留一些痕迹。程序通过搜索这种系统的痕迹,来确定你是否试图分析它。例如,查找调试器引用的注册表项。同时,程序也可以查找系统的文件和目录,查找当前内存的痕迹,或者查看当前进程列表,更普遍的做法是通过FindWindows来查找调试器。
|
|
|
|
|
|
|
|
|
|
## 识别调试器的行为
|
|
|
|
|
在逆向工程中,可以使用断点或单步调试来帮助分析,但执行这些操作时,会修改进程中的代码。因此可以使用几种反调试技术探测INT扫描、完整性校验以及时钟检测等几种类型的调试器行为。
|
|
|
|
|
1. INT扫描
|
|
|
|
|
调试器设置断点的基本机制是用软件中断INT 3,机器码为0xCC,临时替换程序中的一条指令。因此可以通过扫描INT 3修改来检测。
|
|
|
|
|
2. 执行代码校验和检查
|
|
|
|
|
与INT扫描目的相同,但仅执行机器码的CRC或MD5校验和检查。
|
|
|
|
|
3. 时钟检测
|
|
|
|
|
被调试时,进程的运行速度大大降低,常用指令有:`rdstc` `QueryPerformanceCounter` `GetTickCount`,有如下两种方式探测时钟:
|
|
|
|
|
- 记录执行一段操作前后的时间戳
|
|
|
|
|
- 记录触发一个异常前后的时间戳
|
|
|
|
|
## 干扰调试器的功能
|
|
|
|
|
本地存储(TLS)回调:TLS回调被用来在程序入口点执行之前运行代码,这发生在程序刚被加载到调试器时
|
|
|
|
|
使用异常:使用SEH链可以实现异常,程序可以使用异常来破坏或探测调试器,调试器捕获异常后,并不会将处理权立即返回给被调试进程。
|
|
|
|
|
插入中断:插入INT 3、INT 2D、ICE
|
|
|
|
|
## 调试器漏洞
|
|
|
|
|
PE头漏洞、OutputDebugString漏洞
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
# 实验一:软件破解
|
|
|
|
|
## 对象
|
|
|
|
|
[crack.exe](https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553761280/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/crack.exe1),28.0 KB
|
|
|
|
|
- 无保护措施:无壳、未加密、无反调试措施
|
|
|
|
|
- 用户名至少要5个字节
|
|
|
|
|
- 输入错误验证码时输出:“Bad Boy!”
|
|
|
|
|
|
|
|
|
|
## 爆破
|
|
|
|
|
### 查找显示注册结果相关代码
|
|
|
|
|
当输入错误验证码时,程序会输出“Bad Boy”,因此我们将程序拖入IDA,以流程图显示函数内部的跳转。查找“Bad Boy”字符串,我们可以定位到显示注册结果的相关代码:
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553772615/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B71.png)
|
|
|
|
|
|
|
|
|
|
### 查找注册码验证相关代码
|
|
|
|
|
用鼠标选中程序分支点,按空格切换回汇编指令界面
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553773066/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B72.png)
|
|
|
|
|
|
|
|
|
|
可以看到,这条指令位于PE文件的.text节,并且IDA已经自动将地址转换为运行时的内存地址`VA:004010F9`
|
|
|
|
|
|
|
|
|
|
### 修改程序跳转
|
|
|
|
|
- 现在关闭IDA,换用OllyDbg进行动态调试来看看程序时如何分支跳转的`Ctrl+G`直接跳到由IDA得到的`VA:004010F9`处查看那条引起程序分支的关键指令
|
|
|
|
|
- 选中这条指令,按F2设置断点,再按F9运行程序,这时候控制权会回到程序,OllyDbg暂时挂起。到程序提示输入名字和序列号,随意输入(名字大于五个字节),点击ok后,OllyDbg会重新中断程序,收回控制权,如图:
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775053/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B74.png)
|
|
|
|
|
- 验证函数的返回值存于EAX寄存器中,if语句通过以下两条指令执行
|
|
|
|
|
```
|
|
|
|
|
cmp eax,ecx
|
|
|
|
|
jnz xxxxxxx
|
|
|
|
|
```
|
|
|
|
|
- 也就是说,当序列号输入错误时,EAX中的值为0,跳转将被执行。
|
|
|
|
|
如果我们把`jnz`这条指令修改为`jz`,那么整个程序的逻辑就会反过来。
|
|
|
|
|
双击`jnz`这条指令,将其改为`jz`,单击"汇编"将其写入内存
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775817/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B75.png)
|
|
|
|
|
可以看到此时程序执行了相反的路径
|
|
|
|
|
|
|
|
|
|
- 上面只是在内存中修改程序,我们还需要在二进制文件中也修改相应的字节,这里考察VA与文件地址之间的关系
|
|
|
|
|
- 用LordPE打开.exe文件,查看PE文件的节信息
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553776239/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B76.png)
|
|
|
|
|
根据VA与文件地址的换算公式:
|
|
|
|
|
```
|
|
|
|
|
文件偏移地址 = VA - Image Base - 节偏移
|
|
|
|
|
= 0x004010F9 - 0x00400000 - 0
|
|
|
|
|
= 0x10F9
|
|
|
|
|
```
|
|
|
|
|
也就是说,这条指令在PE文件中位于`10F9`字节处,使用010Editer打开crack.exe,将这一字节的`75(JNZ)``改为`74(JZ)``,保存后重新执行,破解成功!
|
|
|
|
|
|
|
|
|
|
## 编写注册机
|
|
|
|
|
### 查找显示注册结果相关代码
|
|
|
|
|
通过查找字符串“good boy”等,我们可以找到显示注册结果的相关代码
|
|
|
|
|
### 查找注册码验证相关代码
|
|
|
|
|
因为检测密钥是否正确时会将结果返回到EAX寄存器中,因此,在检测密钥前必然会对EAX寄存器清空,由此我们可以找到注册码验证的相关代码。
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553858953/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B77.png)
|
|
|
|
|
### 根据注册码验证代码编写注册机
|
|
|
|
|
分析上图算法,按tab键转换为高级语言
|
|
|
|
|
```
|
|
|
|
|
for ( i = 0; i < v6; v12 = v10 )
|
|
|
|
|
v10 = (v6 + v12) * lpStringa[i++];
|
|
|
|
|
if ( (v12 ^ 0xA9F9FA) == atoi(v15) )
|
|
|
|
|
MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);
|
|
|
|
|
```
|
|
|
|
|
可以看出,生成注册码主要在for循环中完成,之后将生成的注册码与输入相比较,判断是否正确。
|
|
|
|
|
所以,只要能弄明白`v6,v12,v10,v15`的含义,我们就可以轻松的编写注册机。
|
|
|
|
|
打开ollybdg,在进入循环之前设下断点,动态调试程序
|
|
|
|
|
```
|
|
|
|
|
004010CC |> /8B4D 10 |mov ecx,[arg.3] //此时ecx为name
|
|
|
|
|
004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908
|
|
|
|
|
004010D2 |. 03D3 |add edx,ebx //edx加上name的长度(ebx)
|
|
|
|
|
004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h
|
|
|
|
|
004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx
|
|
|
|
|
004010DB |. 40 |inc eax //eax加1(初始为0)
|
|
|
|
|
004010DC |. 894D 0C |mov [arg.2],ecx
|
|
|
|
|
004010DF |. 3BC3 |cmp eax,ebx //循环是否结束
|
|
|
|
|
```
|
|
|
|
|
`arg.3`为输入的`name`,`arg.2`初始为`0x1908`,`ebx`为`name`的长度,`eax`每次循环加1直到等于长度
|
|
|
|
|
因此,我们可以对参数的含义进行解释如下
|
|
|
|
|
```
|
|
|
|
|
v12 = 6408; //0x1908
|
|
|
|
|
v10 = 6408; //0x1908
|
|
|
|
|
v6 = len(name);
|
|
|
|
|
v12 = input_serial;
|
|
|
|
|
for ( i = 0; i < v6; i++ ){
|
|
|
|
|
v12 = v10;
|
|
|
|
|
v10 = (v6 + v12) * lpStringa[i];
|
|
|
|
|
}
|
|
|
|
|
if ((v12 ^ 0xA9F9FA) == atoi(v15)){
|
|
|
|
|
MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
可见,`v12^0xA9F9FA`的结果即是正确的注册码,我们编写一个[简单的程序](https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553937750/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/reg.cpp)帮助我们生成注册码:
|
|
|
|
|
```
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include<stdio.h>
|
|
|
|
|
|
|
|
|
|
using namespace::std;
|
|
|
|
|
int main(){
|
|
|
|
|
int v12;
|
|
|
|
|
int v10 = 6408; //0x1908
|
|
|
|
|
string name;
|
|
|
|
|
cout << "请输入name: ";
|
|
|
|
|
cin >> name;
|
|
|
|
|
int len = name.size();
|
|
|
|
|
for(int i = 0; i < len+1; i++ ){
|
|
|
|
|
v12 = v10;
|
|
|
|
|
v10 = (len + v12) * name[i];
|
|
|
|
|
}
|
|
|
|
|
cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
计算出"testname"的对应注册码
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937461/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B79.png)
|
|
|
|
|
注册成功!
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937531/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B711.png)
|
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 实验二:软件反动态调试技术分析
|
|
|
|
|
## 对象
|
|
|
|
|
[CrackMe1.exe](https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779243/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/CrackMe1.exe1) 1641.0 KB
|
|
|
|
|
无保护措施:无壳、未加密、无反调试措施
|
|
|
|
|
使用OllyDbg对该程序进行调试时,程序会自动退出
|
|
|
|
|
|
|
|
|
|
## 要求
|
|
|
|
|
1. 分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的
|
|
|
|
|
2. 分析除父进程检测外,该程序用到的反动态调试技术
|
2019-05-07 11:31:31 +00:00
|
|
|
|
|
|
|
|
|
## 父进程检测
|
|
|
|
|
一般双击运行的进程的父进程都是explorer.exe,但是如果进程被调试父进程则是调试器进程。也就是说如果父进程不是explorer.exe则可以认为程序正在被调试。
|
2019-05-07 11:34:30 +00:00
|
|
|
|
|
|
|
|
|
```
|
2019-05-07 11:31:31 +00:00
|
|
|
|
BOOL IsInDebugger(){
|
|
|
|
|
HANDLE hProcessSnap = NULL;
|
|
|
|
|
char Expchar[] ="\\EXPLORER.EXE";
|
|
|
|
|
char szBuffer[MAX_PATH]={0};
|
|
|
|
|
char FileName[MAX_PATH]={0};
|
|
|
|
|
PROCESSENTRY32 pe32 = {0};
|
|
|
|
|
|
|
|
|
|
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //得到所有进程的列表快照
|
|
|
|
|
if (hProcessSnap == INVALID_HANDLE_VALUE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
|
|
|
|
|
|
|
if (!Process32First(hProcessSnap, &pe32)) // 查找进程
|
|
|
|
|
{
|
|
|
|
|
CloseHandle (hProcessSnap);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do // 遍历所有进程
|
|
|
|
|
{
|
|
|
|
|
if(pe32.th32ProcessID==GetCurrentProcessId() )//判断是否是自己的进程?
|
|
|
|
|
{
|
|
|
|
|
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ParentProcessID); //打开父进程
|
|
|
|
|
if (hProcess)
|
|
|
|
|
{
|
|
|
|
|
if (GetModuleFileNameEx(hProcess, NULL, FileName, MAX_PATH) ) // 得到父进程名
|
|
|
|
|
{
|
|
|
|
|
GetWindowsDirectory(szBuffer,MAX_PATH); //得到系统所在目录
|
|
|
|
|
strcat(szBuffer,Expchar); //组合成类似的字串D:\Winnt\Explorer.EXE
|
|
|
|
|
if(strcmpi (FileName,szBuffer)) // 比较当前是否为Explorer.EXE进程
|
|
|
|
|
{
|
|
|
|
|
return TRUE; // 父进程若不是Explorer.EXE,则是调试器
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FALSE; // 无法获得进程名
|
|
|
|
|
}
|
|
|
|
|
CloseHandle (hProcess);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FALSE;//无权访问该进程
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (Process32Next(hProcessSnap, &pe32));
|
|
|
|
|
CloseHandle (hProcessSnap);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2019-05-07 11:34:30 +00:00
|
|
|
|
```
|
|
|
|
|
|
2019-05-07 11:31:31 +00:00
|
|
|
|
由上述示例代码,我们可以看到父进程检测中调用了GetCurrentProcessId函数来判断。
|
|
|
|
|
因此在Ollydbg中首先找到GetCurrentProcessId模块(Ctrl+N),然后设置断点
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557128745/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/1.png)
|
|
|
|
|
查看断点是否设置成功
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557128848/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/2.png)
|
|
|
|
|
运行该程序,在断点00401932停下,打开任务管理器,CrackMe1的pid为4020=0xFB4
|
|
|
|
|
程序在调用完GetCurrentProcessId后,pid被放入EAX寄存器中,值为0xFB4
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557129711/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/3.png)
|
|
|
|
|
然后调用Openprocess函数,其参数processId为0xFB4,返回进程(CrackMe1)的句柄
|
|
|
|
|
通过ntdll.dll中的LoadLibraryA和GetProcAddress函数找到NtQueryInformationProcess:
|
|
|
|
|
```
|
|
|
|
|
PNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (PNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll"),"NtQueryInformationProcess");
|
|
|
|
|
```
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557131510/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/4.png)
|
|
|
|
|
用OpenProcess获得的句柄设置NtQueryInformationProcess的对应参数,然后调用NtQueryInformationProcess,从其返回值中可以获取到CrackMe1.exe的父进程PID=0xDB4=3508,在任务管理器中查看进程名确实是ollydbg
|
|
|
|
|
然后再次调用openprocess获得父进程的句柄
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557132091/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/5.png)
|
|
|
|
|
最后,调用GetModuleFileNameExA通过OpenProcess返回的句柄获取父进程的文件名:
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557133154/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/6.png)
|
|
|
|
|
至此,成功获取到父进程的文件名,接下来将进行父进程文件名与“c:\windows\explore.exe”的字符串比较。
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557133828/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/7.png)
|
|
|
|
|
EDX中保存explorer字符串,ESI中保存ollydbg字符串
|
|
|
|
|
然后进入循环逐位比较,比较流程是,首先取esi中第一个字符到eax,将EAX的值减去41然后存入exc中,并与19比较大小,判断是否大写,若是则eax加上20转化为小写;转化为小写之后,对edx中的字符做同样操作,然后test eax eax判断是否比较完毕,若没有则逐个比较,直到遇到不相等的字符。
|
|
|
|
|
|
|
|
|
|
## 其他检测
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557227067/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/8.png)
|
|
|
|
|
用EnumWindows枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数,此处的回调函数调用了GetWindowTextA将指定窗口的标题栏(如果有的话)的文字拷贝到缓冲区内
|
|
|
|
|
![](https://res.cloudinary.com/dozyfkbg3/image/upload/v1557227506/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/9.png)
|
|
|
|
|
将得到的窗口标题与”ollydbg”等进行比较,看是否为调试器。
|
|
|
|
|
|
2019-04-02 08:28:32 +00:00
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 实验三:加花加密反调试技术分析
|
|
|
|
|
## 对象
|
|
|
|
|
[CrackMe2.exe](https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779413/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/CrackMe2.exe1) 9.00 KB
|
|
|
|
|
保护措施:部分加花、部分加密、简单反调试
|
2019-05-07 11:31:31 +00:00
|
|
|
|
根据[提示](https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779403/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/Crackme2%E6%8F%90%E7%A4%BA.docx)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-04-02 08:28:32 +00:00
|
|
|
|
|
|
|
|
|
## 内容
|
|
|
|
|
1. 加壳脱壳深入理解
|
|
|
|
|
2. 尝试手动脱壳
|
|
|
|
|
3. 分析CrackMe2.exe中花指令
|
|
|
|
|
4. 分析CrackMe2.exe中的被加密的函数的功能
|
|
|
|
|
5. 分析CrackMe2.exe中的反调试手段
|
|
|
|
|
6. 分析CrackMe2.exe中混合的64位代码的功能
|